Oh you are completely right and I misunderstood the use case.
Somehow I mixed it up with weight reusage, but in your case your approach looks fine.
You would have to make sure to zero out the gradients using the same mask as shown here:
class Net(nn.Module):
    def __init__(self, mask):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(4, 5)
        self.fc2 = nn.Linear(5, 3)
        with torch.no_grad():
            self.fc1.weight.mul_(mask)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        return x

mask = torch.tensor([[1,0,0,1],[1,1,0,0],[1,1,1,0],[0,1,1,1],[0,0,1,1]])
model = Net(mask)

# Check weights
print(model.fc1.weight)

# Dummy training steps
optimizer = torch.optim.Adam(model.parameters(), lr=1.)
data = torch.randn(1, 4)
target = torch.randint(0, 3, (1,))
criterion = nn.CrossEntropyLoss()

for idx in range(3):
    optimizer.zero_grad()
    output = model(data)
    loss = criterion(output, target)
    loss.backward()
    print('Step {}, weight {}, weight.grad {}'.format(
        idx, model.fc1.weight, model.fc1.weight.grad))
    # Zero out gradients
    with torch.no_grad():
        model.fc1.weight.grad.mul_(mask)
    optimizer.step()