diff --git a/src/ModelTree.cc b/src/ModelTree.cc
index 7eef0981b7e54cf2899b5ed47b0b92ac3de77a42..72320d522683b6e1a8ad74b28aedd0ee942ef759 100644
--- a/src/ModelTree.cc
+++ b/src/ModelTree.cc
@@ -283,6 +283,25 @@ ModelTree::computeNonSingularNormalization(const eval_context_t &eval_context)
 
   cout << "Normalizing the " << modelClassName() << "..." << endl;
 
+  /* If the model is purely backward, determine whether all original equations
+     have a single contemporaneous endogenous on the LHS. If this is the case,
+     then first try a normalization by enforcing that each original equation is
+     matched with the endogenous on the LHS. */
+  if (time_recursive_block_decomposition)
+    {
+      auto [normalize_by_lhs, lhs_symbolic_jacobian] { computeLeftHandSideSymbolicJacobian() };
+      if (normalize_by_lhs)
+        try
+          {
+            computeNormalization(lhs_symbolic_jacobian);
+            return true;
+          }
+        catch (ModelNormalizationFailed &e)
+          {
+            cerr << "WARNING: All equations are written so that a single contemporaneous endogenous variable appears on the left-hand side. This suggests a natural normalization of the model. However, variable " << e.unmatched_endo << " could not be matched with an equation. Check whether this is desired." << endl;
+          }
+    }
+
   auto contemporaneous_jacobian {evaluateAndReduceJacobian(eval_context)};
 
   // Compute the maximum value of each row of the contemporaneous Jacobian matrix
@@ -1826,6 +1845,35 @@ ModelTree::computeSymbolicJacobian(bool contemporaneous_only) const
   return symbolic_jacobian;
 }
 
+pair<bool, ModelTree::jacob_map_t>
+ModelTree::computeLeftHandSideSymbolicJacobian() const
+{
+  jacob_map_t lhs_symbolic_jacobian;
+  auto not_contemporaneous = [](const pair<int, int> &p) { return p.second != 0; };
+
+  for (int eq {0}; eq < static_cast<int>(equations.size()); eq++)
+    if (equations_lineno[eq]) // Hand-written equation: test whether LHS has single contemporaneous endo
+      {
+        set<pair<int, int>> endos_and_lags;
+        equations[eq]->arg1->collectEndogenous(endos_and_lags);
+        erase_if(endos_and_lags, not_contemporaneous);
+        if (endos_and_lags.size() == 1)
+          lhs_symbolic_jacobian.try_emplace({ eq, endos_and_lags.begin()->first }, 1);
+        else
+          return { false, {} };
+      }
+    else // Generated equation: keep all endos on both LHS and RHS
+      {
+        set<pair<int, int>> endos_and_lags;
+        equations[eq]->collectEndogenous(endos_and_lags);
+        erase_if(endos_and_lags, not_contemporaneous);
+        for (const auto &[endo, lag] : endos_and_lags)
+          lhs_symbolic_jacobian.try_emplace({ eq, endo }, 1);
+      }
+
+  return { true, lhs_symbolic_jacobian };
+}
+
 void
 ModelTree::updateReverseVariableEquationOrderings()
 {
diff --git a/src/ModelTree.hh b/src/ModelTree.hh
index 7ba465a5b8244b04b044c3dbe022115cbc659a1a..2cc2be0cd3ee8547e6a70d24997d2f8555a51b6b 100644
--- a/src/ModelTree.hh
+++ b/src/ModelTree.hh
@@ -433,6 +433,17 @@ private:
      variables; otherwise also considers leads and lags. */
   jacob_map_t computeSymbolicJacobian(bool contemporaneous_only) const;
 
+  /* Compute a pseudo-Jacobian whose all elements are either zero or one.
+     For the equations that were originally written by the user (identified as
+     those having an associated line number), checks whether there is a single
+     contemporaneous endogenous on the left-hand side; if yes, only this
+     endogenous is associated with a one on the line of the corresponding
+     equation; otherwise, returns false as the first output argument and
+     aborts the computation.
+     For the other equations, fills the corresponding lines as is done
+     by computeSymbolicJacobian(true). */
+  pair<bool, jacob_map_t> computeLeftHandSideSymbolicJacobian() const;
+
   // Compute {var,eq}_idx_orig2block from {var,eq}_idx_block2orig
   void updateReverseVariableEquationOrderings();