Parameter sharing / weight constraints in Neural Networks
I'll list two approaches, either of which should work.

Projected gradient descent

One general approach would be to use projected gradient descent, which provides a way to accommodate these kinds of constraints.  For specific kinds of constraints there may be a better way.

Let's recall how we train neural networks.  We have an objective function $\Psi$ that computes the total loss, as a function of the weights $w$.  Training a neural network amounts to solving the optimization problem "minimize $\Psi(w)$".  This is typically done using (stochastic) gradient descent to find the weights $w$ that minimize $\Psi(w)$.  In each iteration, you take a single gradient step to update $w$ (backpropagation is just a way to help you compute the gradient $\nabla \Psi(w)$, to help you take this step).

Now you want to add some constraints on $w$.  Let $\mathcal{R}$ denote the region (linear subspace) of $w$'s that satisfy all your constraints.  Now we want to solve the optimization problem "minimize $\Psi(w)$ subject to $w \in \mathcal{R}$".  One standard way to solve such an optimization problem is to use projected gradient descent: in each iteration, you take a single gradient step to update $w$, then project $w$ to the nearest point in $\mathcal{R}$; and repeat.  So this amounts to doing the standard backprop training procedure for a neural network, but after each weight update, projecting the weights to the nearest valid value that satisfies all the constraints.  You can read more about projected gradient descent in standard resources. In your situation, it is easy to project onto a linear subspace; this is a simple matter of linear algebra.  So projected gradient descent should be straightforward to apply.  It also shouldn't be too hard to add the projection step, in a framework like Tensorflow.  This also has the nice benefit of generalizing beyond linear constraints.

Reparameterization

The other plausible approach would be a reparameterization trick.  If you have $m$ weights, your region $\mathcal{R}$ has the form $\{w : Aw=c\}$, where $A$ is a $m \times n$ matrix and $c$ a constant $m$-vector.  This can be reparametrized into the form $\{Bv\}$ where $B$ is a $n\times n-m$ matrix and $v$ ranges over all possible $n-m$-vectors.  In other words, we can find a matrix $B$ such that every valid weight value $w$ can be expressed as $w=Bv$ for some $v$.  (I think you can compute $B$ as the pseudoinverse of $A$.)  Then, instead of solving the optimization problem "minimize $\Psi(w)$ subject to $w \in \mathcal{R}$", you can solve the optimization problem "minimize $\Psi(Bv)$", where now there are no constraints on $v$.  This in turn can be done using gradient descent.

Once you've found the matrix $B$, you'll probably find the latter approach very easy to implement in frameworks like Tensorflow; you just let $v$ be the variables you are trying to solve for, compute $w$ from $v$ using $w=Bv$, and then the neural network uses these derived weights $w$, and you can ask Tensorflow to minimize the loss as usual.