The indexing of the input data and “selectively” calling backward works as expected in this code snippet:
class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.base = nn.Linear(1, 10)
        self.head1 = nn.Linear(10, 10)
        self.head2 = nn.Linear(10, 10)
        
    def forward(self, x):
        idx1 = (x == 0).nonzero()
        idx2 = (x == 1).nonzero()
        
        # base
        x = self.base(x)
        
        # heads
        x1 = torch.index_select(x, 0, idx1[:, 0])
        x2 = torch.index_select(x, 0, idx2[:, 0])
        
        x1 = self.head1(x1)
        x2 = self.head2(x2)
        
        return x1, x2

model = MyModel()
x = torch.randint(0, 2, (100, 1)).float()
out1, out2 = model(x)
print(out1.shape, out2.shape)

for name, param in model.named_parameters():
    print(name, param.grad)

out1.mean().backward(retain_graph=True)
for name, param in model.named_parameters():
    print(name, param.grad)

out2.mean().backward()
for name, param in model.named_parameters():
    print(name, param.grad)

As you can see, the gradients of the parameters of head2 will be None after the first backward call and will only be populated after out2.mean().backward() is called.
I guess the indexing in your code might not work as expected and might select all samples from the batch dimension. Could you verify that x_t and x_c contain separate sets of the input data and if so compare your approach to my example code snippet?