Hello,
I wrote a small snippet, it seems that the first options you mentioned works for me.
import torch
import torch.nn as nn
import torch.nn.functional as f
class Unit(nn.Module):
    def __init__(self):
        super(Unit, self).__init__()
        self.linear = nn.Linear(3,3,bias=False)

    def forward(self, input):
        self.linear.weight = nn.Parameter(f.relu(self.linear.weight), requires_grad=True)
        output = self.linear(input)
        return output

random_input = torch.randn(3,3)
random_target = torch.randn(3,3)
criterion = nn.MSELoss()

unit = Unit()
loss = criterion(unit(random_input), random_target)
print("linear weight", unit.linear.weight)  # here linear.weight is non-negative
loss.backward()
print(unit.linear.weight.requires_grad)
print(unit.linear.weight.grad) # here linear.weight.grad is not None