You can’t reattach, but you can


z_d = z.detach().requires_grad_() and similarly theta_d.
pred_mean = decoder(x, z_d, theta_d)
compute x_grad, z_d_grad, theta_d_grad as grad of pred_mean w.r.t. x, z_d, theta_d.

theta.backward(theta_d_grad), analogously for z.

You end up with x.grad, y.grad gradients of x, y considering the decoder input of x fixed (so only through theta and z), x_grad the gradient w.r.t. x considering z, and theta fixed.
Best regards
Thomas