diff --git a/ProcessLib/HydroMechanics/HydroMechanicsFEM-impl.h b/ProcessLib/HydroMechanics/HydroMechanicsFEM-impl.h
index 00177dac076842540924c85b855c6329ed3ebd32..8e9e177562de606254bfea781776ba26ddc3edd2 100644
--- a/ProcessLib/HydroMechanics/HydroMechanicsFEM-impl.h
+++ b/ProcessLib/HydroMechanics/HydroMechanicsFEM-impl.h
@@ -796,5 +796,25 @@ void HydroMechanicsLocalAssembler<ShapeFunctionDisplacement,
     }
 }
 
+template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
+          typename IntegrationMethod, int DisplacementDim>
+unsigned HydroMechanicsLocalAssembler<
+    ShapeFunctionDisplacement, ShapeFunctionPressure, IntegrationMethod,
+    DisplacementDim>::getNumberOfIntegrationPoints() const
+{
+    return _integration_method.getNumberOfPoints();
+}
+
+template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
+          typename IntegrationMethod, int DisplacementDim>
+typename MaterialLib::Solids::MechanicsBase<
+    DisplacementDim>::MaterialStateVariables const&
+HydroMechanicsLocalAssembler<ShapeFunctionDisplacement, ShapeFunctionPressure,
+                             IntegrationMethod, DisplacementDim>::
+    getMaterialStateVariablesAt(unsigned integration_point) const
+{
+    return *_ip_data[integration_point].material_state_variables;
+}
+
 }  // namespace HydroMechanics
 }  // namespace ProcessLib
diff --git a/ProcessLib/HydroMechanics/HydroMechanicsFEM.h b/ProcessLib/HydroMechanics/HydroMechanicsFEM.h
index c3cfe2fade5d587e81623b05f374adb8cdaeb971..217a7689ef45b4a46f7427eec5822145f902e4ec 100644
--- a/ProcessLib/HydroMechanics/HydroMechanicsFEM.h
+++ b/ProcessLib/HydroMechanics/HydroMechanicsFEM.h
@@ -106,7 +106,8 @@ struct SecondaryData
 
 template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
           typename IntegrationMethod, int DisplacementDim>
-class HydroMechanicsLocalAssembler : public LocalAssemblerInterface
+class HydroMechanicsLocalAssembler
+    : public LocalAssemblerInterface<DisplacementDim>
 {
 public:
     using ShapeMatricesTypeDisplacement =
@@ -436,6 +437,12 @@ private:
         std::vector<double>& local_b_data, std::vector<double>& local_Jac_data,
         LocalCoupledSolutions const& local_coupled_solutions);
 
+    unsigned getNumberOfIntegrationPoints() const override;
+
+    typename MaterialLib::Solids::MechanicsBase<
+        DisplacementDim>::MaterialStateVariables const&
+    getMaterialStateVariablesAt(unsigned integration_point) const override;
+
 private:
     HydroMechanicsProcessData<DisplacementDim>& _process_data;
 
diff --git a/ProcessLib/HydroMechanics/HydroMechanicsProcess.cpp b/ProcessLib/HydroMechanics/HydroMechanicsProcess.cpp
index a4557810dc973bfb3f5edb5e4769dddf695757b3..96467d80c859bb5fe24729d9b1e9dc56b53022da 100644
--- a/ProcessLib/HydroMechanics/HydroMechanicsProcess.cpp
+++ b/ProcessLib/HydroMechanics/HydroMechanicsProcess.cpp
@@ -12,14 +12,13 @@
 
 #include <cassert>
 
+#include "HydroMechanicsFEM.h"
+#include "HydroMechanicsProcessData.h"
 #include "MeshLib/Elements/Utils.h"
 #include "NumLib/DOF/ComputeSparsityPattern.h"
+#include "ProcessLib/Deformation/SolidMaterialInternalToSecondaryVariables.h"
 #include "ProcessLib/HydroMechanics/CreateLocalAssemblers.h"
 #include "ProcessLib/Process.h"
-
-#include "HydroMechanicsFEM.h"
-#include "HydroMechanicsProcessData.h"
-
 namespace ProcessLib
 {
 namespace HydroMechanics
@@ -208,77 +207,68 @@ void HydroMechanicsProcess<DisplacementDim>::initializeConcreteProcess(
         _local_assemblers, mesh.isAxiallySymmetric(), integration_order,
         _process_data);
 
-    _secondary_variables.addSecondaryVariable(
-        "sigma_xx",
-        makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtSigmaXX));
+    auto add_secondary_variable = [&](std::string const& name,
+                                      int const num_components,
+                                      auto get_ip_values_function) {
+        _secondary_variables.addSecondaryVariable(
+            name,
+            makeExtrapolator(num_components, getExtrapolator(),
+                             _local_assemblers,
+                             std::move(get_ip_values_function)));
+    };
+
+    add_secondary_variable(
+        "sigma_xx", 1, &LocalAssemblerIF::getIntPtSigmaXX);
 
-    _secondary_variables.addSecondaryVariable(
-        "sigma_yy",
-        makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtSigmaYY));
+    add_secondary_variable(
+        "sigma_yy", 1, &LocalAssemblerIF::getIntPtSigmaYY);
 
-    _secondary_variables.addSecondaryVariable(
-        "sigma_zz",
-        makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtSigmaZZ));
+    add_secondary_variable(
+        "sigma_zz", 1, &LocalAssemblerIF::getIntPtSigmaZZ);
 
-    _secondary_variables.addSecondaryVariable(
-        "sigma_xy",
-        makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtSigmaXY));
+    add_secondary_variable(
+        "sigma_xy", 1, &LocalAssemblerIF::getIntPtSigmaXY);
 
     if (DisplacementDim == 3)
     {
-        _secondary_variables.addSecondaryVariable(
-            "sigma_xz",
-            makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                             &LocalAssemblerInterface::getIntPtSigmaXZ));
+        add_secondary_variable(
+            "sigma_xz", 1, &LocalAssemblerIF::getIntPtSigmaXZ);
 
-        _secondary_variables.addSecondaryVariable(
-            "sigma_yz",
-            makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                             &LocalAssemblerInterface::getIntPtSigmaYZ));
+        add_secondary_variable(
+            "sigma_yz", 1, &LocalAssemblerIF::getIntPtSigmaYZ);
     }
 
-    _secondary_variables.addSecondaryVariable(
-        "epsilon_xx",
-        makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtEpsilonXX));
+    add_secondary_variable(
+        "epsilon_xx", 1, &LocalAssemblerIF::getIntPtEpsilonXX);
 
-    _secondary_variables.addSecondaryVariable(
-        "epsilon_yy",
-        makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtEpsilonYY));
+    add_secondary_variable(
+        "epsilon_yy", 1, &LocalAssemblerIF::getIntPtEpsilonYY);
 
-    _secondary_variables.addSecondaryVariable(
-        "epsilon_zz",
-        makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtEpsilonZZ));
+    add_secondary_variable(
+        "epsilon_zz", 1, &LocalAssemblerIF::getIntPtEpsilonZZ);
 
-    _secondary_variables.addSecondaryVariable(
-        "epsilon_xy",
-        makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtEpsilonXY));
+    add_secondary_variable(
+        "epsilon_xy", 1, &LocalAssemblerIF::getIntPtEpsilonXY);
 
     if (DisplacementDim == 3)
     {
-        _secondary_variables.addSecondaryVariable(
-            "epsilon_xz",
-            makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                             &LocalAssemblerInterface::getIntPtEpsilonXZ));
+        add_secondary_variable(
+            "epsilon_xz", 1, &LocalAssemblerIF::getIntPtEpsilonXZ);
 
-        _secondary_variables.addSecondaryVariable(
-            "epsilon_yz",
-            makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                             &LocalAssemblerInterface::getIntPtEpsilonYZ));
+        add_secondary_variable(
+            "epsilon_yz", 1, &LocalAssemblerIF::getIntPtEpsilonYZ);
     }
 
-    _secondary_variables.addSecondaryVariable(
-        "velocity",
-        makeExtrapolator(mesh.getDimension(), getExtrapolator(),
-                         _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtDarcyVelocity));
+    add_secondary_variable("velocity",
+                           DisplacementDim,
+                           &LocalAssemblerIF::getIntPtDarcyVelocity);
+
+    //
+    // enable output of internal variables defined by material models
+    //
+    ProcessLib::Deformation::solidMaterialInternalToSecondaryVariables<
+        LocalAssemblerIF>(_process_data.solid_materials,
+                                 add_secondary_variable);
 
     _process_data.pressure_interpolated =
         MeshLib::getOrCreateMeshProperty<double>(
@@ -357,7 +347,7 @@ void HydroMechanicsProcess<DisplacementDim>::initializeConcreteProcess(
 
     // Initialize local assemblers after all variables have been set.
     GlobalExecutor::executeMemberOnDereferenced(
-        &LocalAssemblerInterface::initialize, _local_assemblers,
+        &LocalAssemblerIF::initialize, _local_assemblers,
         *_local_to_global_index_map);
 }
 
@@ -483,7 +473,7 @@ void HydroMechanicsProcess<DisplacementDim>::preTimestepConcreteProcess(
         ProcessLib::ProcessVariable const& pv =
             getProcessVariables(process_id)[0];
         GlobalExecutor::executeSelectedMemberOnDereferenced(
-            &LocalAssemblerInterface::preTimestep, _local_assemblers,
+            &LocalAssemblerIF::preTimestep, _local_assemblers,
             pv.getActiveElementIDs(), *_local_to_global_index_map,
             *x[process_id], t, dt);
     }
@@ -497,7 +487,7 @@ void HydroMechanicsProcess<DisplacementDim>::postTimestepConcreteProcess(
     DBUG("PostTimestep HydroMechanicsProcess.");
     ProcessLib::ProcessVariable const& pv = getProcessVariables(process_id)[0];
     GlobalExecutor::executeSelectedMemberOnDereferenced(
-        &LocalAssemblerInterface::postTimestep, _local_assemblers,
+        &LocalAssemblerIF::postTimestep, _local_assemblers,
         pv.getActiveElementIDs(), getDOFTable(process_id), *x[process_id], t,
         dt);
 }
@@ -516,7 +506,7 @@ void HydroMechanicsProcess<DisplacementDim>::postNonLinearSolverConcreteProcess(
     // Calculate strain, stress or other internal variables of mechanics.
     ProcessLib::ProcessVariable const& pv = getProcessVariables(process_id)[0];
     GlobalExecutor::executeSelectedMemberOnDereferenced(
-        &LocalAssemblerInterface::postNonLinearSolver, _local_assemblers,
+        &LocalAssemblerIF::postNonLinearSolver, _local_assemblers,
         pv.getActiveElementIDs(), getDOFTable(process_id), x, t, dt,
         _use_monolithic_scheme);
 }
@@ -528,7 +518,7 @@ void HydroMechanicsProcess<DisplacementDim>::computeSecondaryVariableConcrete(
     DBUG("Compute the secondary variables for HydroMechanicsProcess.");
     ProcessLib::ProcessVariable const& pv = getProcessVariables(process_id)[0];
     GlobalExecutor::executeSelectedMemberOnDereferenced(
-        &LocalAssemblerInterface::computeSecondaryVariable, _local_assemblers,
+        &LocalAssemblerIF::computeSecondaryVariable, _local_assemblers,
         pv.getActiveElementIDs(), getDOFTable(process_id), t, x,
         _coupled_solutions);
 }
diff --git a/ProcessLib/HydroMechanics/HydroMechanicsProcess.h b/ProcessLib/HydroMechanics/HydroMechanicsProcess.h
index 5768ae438704eaf5a5052b6b47ef66d513b891f1..d1e254334bca1389cb6d07a42cf95bcadc7bee43 100644
--- a/ProcessLib/HydroMechanics/HydroMechanicsProcess.h
+++ b/ProcessLib/HydroMechanics/HydroMechanicsProcess.h
@@ -62,6 +62,8 @@ public:
         const int process_id) const override;
 
 private:
+    using LocalAssemblerIF = LocalAssemblerInterface<DisplacementDim>;
+
     void constructDofTable() override;
 
     void initializeConcreteProcess(
@@ -103,7 +105,7 @@ private:
     std::unique_ptr<MeshLib::MeshSubset const> _mesh_subset_base_nodes;
     HydroMechanicsProcessData<DisplacementDim> _process_data;
 
-    std::vector<std::unique_ptr<LocalAssemblerInterface>> _local_assemblers;
+    std::vector<std::unique_ptr<LocalAssemblerIF>> _local_assemblers;
 
     std::unique_ptr<NumLib::LocalToGlobalIndexMap>
         _local_to_global_index_map_single_component;
diff --git a/ProcessLib/HydroMechanics/LocalAssemblerInterface.h b/ProcessLib/HydroMechanics/LocalAssemblerInterface.h
index c9f999626b5d4a11f5712bb5c318f51d647b5203..7781266d0fb046b50db7ea7cbba11d9885394cb8 100644
--- a/ProcessLib/HydroMechanics/LocalAssemblerInterface.h
+++ b/ProcessLib/HydroMechanics/LocalAssemblerInterface.h
@@ -10,6 +10,7 @@
 
 #pragma once
 
+#include "MaterialLib/SolidModels/MechanicsBase.h"
 #include "NumLib/Extrapolation/ExtrapolatableElement.h"
 #include "ProcessLib/LocalAssemblerInterface.h"
 
@@ -17,9 +18,9 @@ namespace ProcessLib
 {
 namespace HydroMechanics
 {
-struct LocalAssemblerInterface
-    : public ProcessLib::LocalAssemblerInterface,
-      public NumLib::ExtrapolatableElement
+template <int DisplacementDim>
+struct LocalAssemblerInterface : public ProcessLib::LocalAssemblerInterface,
+                                 public NumLib::ExtrapolatableElement
 {
     virtual std::size_t setIPDataInitialConditions(
         std::string const& name, double const* values,
@@ -106,6 +107,13 @@ struct LocalAssemblerInterface
         std::vector<GlobalVector*> const& x,
         std::vector<NumLib::LocalToGlobalIndexMap const*> const& dof_table,
         std::vector<double>& cache) const = 0;
+
+    // TODO move to NumLib::ExtrapolatableElement
+    virtual unsigned getNumberOfIntegrationPoints() const = 0;
+
+    virtual typename MaterialLib::Solids::MechanicsBase<
+        DisplacementDim>::MaterialStateVariables const&
+    getMaterialStateVariablesAt(unsigned /*integration_point*/) const = 0;
 };
 
 }  // namespace HydroMechanics
diff --git a/ProcessLib/RichardsMechanics/LocalAssemblerInterface.h b/ProcessLib/RichardsMechanics/LocalAssemblerInterface.h
index eaf661fd32f27264a226909763c03c99bc7dd4b8..c4864173aa7d4e9f623a7b0a3da1fa3910561438 100644
--- a/ProcessLib/RichardsMechanics/LocalAssemblerInterface.h
+++ b/ProcessLib/RichardsMechanics/LocalAssemblerInterface.h
@@ -10,6 +10,7 @@
 
 #pragma once
 
+#include "MaterialLib/SolidModels/MechanicsBase.h"
 #include "NumLib/Extrapolation/ExtrapolatableElement.h"
 #include "ProcessLib/LocalAssemblerInterface.h"
 
@@ -17,6 +18,7 @@ namespace ProcessLib
 {
 namespace RichardsMechanics
 {
+template <int DisplacementDim>
 struct LocalAssemblerInterface : public ProcessLib::LocalAssemblerInterface,
                                  public NumLib::ExtrapolatableElement
 {
@@ -43,6 +45,13 @@ struct LocalAssemblerInterface : public ProcessLib::LocalAssemblerInterface,
         std::vector<GlobalVector*> const& x,
         std::vector<NumLib::LocalToGlobalIndexMap const*> const& dof_table,
         std::vector<double>& cache) const = 0;
+
+    // TODO move to NumLib::ExtrapolatableElement
+    virtual unsigned getNumberOfIntegrationPoints() const = 0;
+
+    virtual typename MaterialLib::Solids::MechanicsBase<
+        DisplacementDim>::MaterialStateVariables const&
+    getMaterialStateVariablesAt(unsigned /*integration_point*/) const = 0;
 };
 
 }  // namespace RichardsMechanics
diff --git a/ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h b/ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h
index c3d7b3ecf5ec20967a65e083b343efa33dc2606a..d4450f4f295d16d82dca4e385f7ca26ef6c54f35 100644
--- a/ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h
+++ b/ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h
@@ -886,5 +886,25 @@ void RichardsMechanicsLocalAssembler<ShapeFunctionDisplacement,
                          *_process_data.pressure_interpolated);
 }
 
+template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
+          typename IntegrationMethod, int DisplacementDim>
+unsigned RichardsMechanicsLocalAssembler<
+    ShapeFunctionDisplacement, ShapeFunctionPressure, IntegrationMethod,
+    DisplacementDim>::getNumberOfIntegrationPoints() const
+{
+    return _integration_method.getNumberOfPoints();
+}
+
+template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
+          typename IntegrationMethod, int DisplacementDim>
+typename MaterialLib::Solids::MechanicsBase<
+    DisplacementDim>::MaterialStateVariables const&
+RichardsMechanicsLocalAssembler<
+    ShapeFunctionDisplacement, ShapeFunctionPressure, IntegrationMethod,
+    DisplacementDim>::getMaterialStateVariablesAt(unsigned integration_point)
+    const
+{
+    return *_ip_data[integration_point].material_state_variables;
+}
 }  // namespace RichardsMechanics
 }  // namespace ProcessLib
diff --git a/ProcessLib/RichardsMechanics/RichardsMechanicsFEM.h b/ProcessLib/RichardsMechanics/RichardsMechanicsFEM.h
index 45db4b3697186b755a912d5a47f4b156832c5b78..89ce9cfa5068b6afe727e64e5d9d17e395712217 100644
--- a/ProcessLib/RichardsMechanics/RichardsMechanicsFEM.h
+++ b/ProcessLib/RichardsMechanics/RichardsMechanicsFEM.h
@@ -42,7 +42,8 @@ struct SecondaryData
 
 template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
           typename IntegrationMethod, int DisplacementDim>
-class RichardsMechanicsLocalAssembler : public LocalAssemblerInterface
+class RichardsMechanicsLocalAssembler
+    : public LocalAssemblerInterface<DisplacementDim>
 {
 public:
     using ShapeMatricesTypeDisplacement =
@@ -244,6 +245,12 @@ private:
         std::vector<double>& local_b_data, std::vector<double>& local_Jac_data,
         LocalCoupledSolutions const& local_coupled_solutions);
 
+    unsigned getNumberOfIntegrationPoints() const override;
+
+    typename MaterialLib::Solids::MechanicsBase<
+        DisplacementDim>::MaterialStateVariables const&
+    getMaterialStateVariablesAt(unsigned integration_point) const override;
+
 private:
     RichardsMechanicsProcessData<DisplacementDim>& _process_data;
 
diff --git a/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.cpp b/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.cpp
index 33d9b5debec87dda9d1ba1830507ea5678006b1e..fd5ba4b532579916ef426a52254a19c634294e05 100644
--- a/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.cpp
+++ b/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.cpp
@@ -14,9 +14,9 @@
 
 #include "MeshLib/Elements/Utils.h"
 #include "NumLib/DOF/ComputeSparsityPattern.h"
+#include "ProcessLib/Deformation/SolidMaterialInternalToSecondaryVariables.h"
 #include "ProcessLib/Process.h"
 #include "ProcessLib/RichardsMechanics/CreateLocalAssemblers.h"
-
 #include "RichardsMechanicsFEM.h"
 #include "RichardsMechanicsProcessData.h"
 
@@ -168,29 +168,39 @@ void RichardsMechanicsProcess<DisplacementDim>::initializeConcreteProcess(
         _local_assemblers, mesh.isAxiallySymmetric(), integration_order,
         _process_data);
 
-    _secondary_variables.addSecondaryVariable(
-        "sigma",
-        makeExtrapolator(MathLib::KelvinVector::KelvinVectorType<
-                             DisplacementDim>::RowsAtCompileTime,
-                         getExtrapolator(), _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtSigma));
-
-    _secondary_variables.addSecondaryVariable(
-        "epsilon",
-        makeExtrapolator(MathLib::KelvinVector::KelvinVectorType<
-                             DisplacementDim>::RowsAtCompileTime,
-                         getExtrapolator(), _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtEpsilon));
-
-    _secondary_variables.addSecondaryVariable(
-        "velocity",
-        makeExtrapolator(DisplacementDim, getExtrapolator(), _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtDarcyVelocity));
-
-    _secondary_variables.addSecondaryVariable(
-        "saturation",
-        makeExtrapolator(1, getExtrapolator(), _local_assemblers,
-                         &LocalAssemblerInterface::getIntPtSaturation));
+    auto add_secondary_variable = [&](std::string const& name,
+                                      int const num_components,
+                                      auto get_ip_values_function) {
+        _secondary_variables.addSecondaryVariable(
+            name,
+            makeExtrapolator(num_components, getExtrapolator(),
+                             _local_assemblers,
+                             std::move(get_ip_values_function)));
+    };
+
+    add_secondary_variable("sigma",
+                           MathLib::KelvinVector::KelvinVectorType<
+                               DisplacementDim>::RowsAtCompileTime,
+                           &LocalAssemblerIF::getIntPtSigma);
+
+    add_secondary_variable("epsilon",
+                           MathLib::KelvinVector::KelvinVectorType<
+                               DisplacementDim>::RowsAtCompileTime,
+                           &LocalAssemblerIF::getIntPtEpsilon);
+
+    add_secondary_variable("velocity",
+                           DisplacementDim,
+                           &LocalAssemblerIF::getIntPtDarcyVelocity);
+
+    add_secondary_variable("saturation", 1,
+                           &LocalAssemblerIF::getIntPtSaturation);
+
+    //
+    // enable output of internal variables defined by material models
+    //
+    ProcessLib::Deformation::solidMaterialInternalToSecondaryVariables<
+        LocalAssemblerIF>(_process_data.solid_materials,
+                                 add_secondary_variable);
 
     _process_data.element_saturation = MeshLib::getOrCreateMeshProperty<double>(
         const_cast<MeshLib::Mesh&>(mesh), "saturation_avg",
@@ -203,7 +213,7 @@ void RichardsMechanicsProcess<DisplacementDim>::initializeConcreteProcess(
 
     // Initialize local assemblers after all variables have been set.
     GlobalExecutor::executeMemberOnDereferenced(
-        &LocalAssemblerInterface::initialize, _local_assemblers,
+        &LocalAssemblerIF::initialize, _local_assemblers,
         *_local_to_global_index_map);
 }
 
@@ -332,7 +342,7 @@ void RichardsMechanicsProcess<DisplacementDim>::preTimestepConcreteProcess(
         ProcessLib::ProcessVariable const& pv =
             getProcessVariables(process_id)[0];
         GlobalExecutor::executeSelectedMemberOnDereferenced(
-            &LocalAssemblerInterface::preTimestep, _local_assemblers,
+            &LocalAssemblerIF::preTimestep, _local_assemblers,
             pv.getActiveElementIDs(), *_local_to_global_index_map,
             *x[process_id], t, dt);
     }
@@ -355,7 +365,7 @@ void RichardsMechanicsProcess<
 
     // Calculate strain, stress or other internal variables of mechanics.
     GlobalExecutor::executeSelectedMemberOnDereferenced(
-        &LocalAssemblerInterface::postNonLinearSolver, _local_assemblers,
+        &LocalAssemblerIF::postNonLinearSolver, _local_assemblers,
         pv.getActiveElementIDs(), getDOFTable(process_id), x, t, dt,
         _use_monolithic_scheme);
 }
@@ -370,7 +380,7 @@ void RichardsMechanicsProcess<
     ProcessLib::ProcessVariable const& pv = getProcessVariables(process_id)[0];
 
     GlobalExecutor::executeSelectedMemberOnDereferenced(
-        &LocalAssemblerInterface::computeSecondaryVariable, _local_assemblers,
+        &LocalAssemblerIF::computeSecondaryVariable, _local_assemblers,
         pv.getActiveElementIDs(), getDOFTable(process_id), t, x,
         _coupled_solutions);
 }
diff --git a/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.h b/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.h
index f14bb2bec8acf27adb5754350edf435e004204d4..c50b236dc46ad951c7ff5a251d9977681539eccb 100644
--- a/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.h
+++ b/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.h
@@ -18,8 +18,6 @@ namespace ProcessLib
 {
 namespace RichardsMechanics
 {
-struct LocalAssemblerInterface;
-
 /// Linear kinematics poro-mechanical/biphasic (fluid-solid mixture) model.
 ///
 /// The mixture momentum balance and the mixture mass balance are solved under
@@ -64,6 +62,8 @@ public:
         const int process_id) const override;
 
 private:
+    using LocalAssemblerIF = LocalAssemblerInterface<DisplacementDim>;
+
     void constructDofTable() override;
 
     void initializeConcreteProcess(
@@ -100,7 +100,7 @@ private:
     std::unique_ptr<MeshLib::MeshSubset const> _mesh_subset_base_nodes;
     RichardsMechanicsProcessData<DisplacementDim> _process_data;
 
-    std::vector<std::unique_ptr<LocalAssemblerInterface>> _local_assemblers;
+    std::vector<std::unique_ptr<LocalAssemblerIF>> _local_assemblers;
 
     std::unique_ptr<NumLib::LocalToGlobalIndexMap>
         _local_to_global_index_map_single_component;
diff --git a/ProcessLib/ThermoMechanics/LocalAssemblerInterface.h b/ProcessLib/ThermoMechanics/LocalAssemblerInterface.h
index 4ff9813373b305fd5dc0888c10884ee65f1fda0f..07f661cffcd8664c687f77da83748d693049dee4 100644
--- a/ProcessLib/ThermoMechanics/LocalAssemblerInterface.h
+++ b/ProcessLib/ThermoMechanics/LocalAssemblerInterface.h
@@ -12,6 +12,7 @@
 
 #include <vector>
 
+#include "MaterialLib/SolidModels/MechanicsBase.h"
 #include "NumLib/Extrapolation/ExtrapolatableElement.h"
 #include "ProcessLib/LocalAssemblerInterface.h"
 
@@ -19,6 +20,7 @@ namespace ProcessLib
 {
 namespace ThermoMechanics
 {
+template <int DisplacementDim>
 struct ThermoMechanicsLocalAssemblerInterface
     : public ProcessLib::LocalAssemblerInterface,
       public NumLib::ExtrapolatableElement
@@ -44,6 +46,13 @@ struct ThermoMechanicsLocalAssemblerInterface
         std::vector<GlobalVector*> const& x,
         std::vector<NumLib::LocalToGlobalIndexMap const*> const& dof_table,
         std::vector<double>& cache) const = 0;
+
+    // TODO move to NumLib::ExtrapolatableElement
+    virtual unsigned getNumberOfIntegrationPoints() const = 0;
+
+    virtual typename MaterialLib::Solids::MechanicsBase<
+        DisplacementDim>::MaterialStateVariables const&
+    getMaterialStateVariablesAt(unsigned /*integration_point*/) const = 0;
 };
 
 }  // namespace ThermoMechanics
diff --git a/ProcessLib/ThermoMechanics/ThermoMechanicsFEM-impl.h b/ProcessLib/ThermoMechanics/ThermoMechanicsFEM-impl.h
index 91157581dd5937265c36c64c160dbee8aaab2f59..44499e06acf7b89900fc10a861fa767fe76f5090 100644
--- a/ProcessLib/ThermoMechanics/ThermoMechanicsFEM-impl.h
+++ b/ProcessLib/ThermoMechanics/ThermoMechanicsFEM-impl.h
@@ -753,5 +753,24 @@ ThermoMechanicsLocalAssembler<ShapeFunction, IntegrationMethod,
     return ip_epsilon_m_values;
 }
 
+template <typename ShapeFunction, typename IntegrationMethod,
+          int DisplacementDim>
+unsigned ThermoMechanicsLocalAssembler<
+    ShapeFunction, IntegrationMethod,
+    DisplacementDim>::getNumberOfIntegrationPoints() const
+{
+    return _integration_method.getNumberOfPoints();
+}
+
+template <typename ShapeFunction, typename IntegrationMethod,
+          int DisplacementDim>
+typename MaterialLib::Solids::MechanicsBase<
+    DisplacementDim>::MaterialStateVariables const&
+ThermoMechanicsLocalAssembler<ShapeFunction, IntegrationMethod,
+                              DisplacementDim>::
+    getMaterialStateVariablesAt(unsigned integration_point) const
+{
+    return *_ip_data[integration_point].material_state_variables;
+}
 }  // namespace ThermoMechanics
 }  // namespace ProcessLib
diff --git a/ProcessLib/ThermoMechanics/ThermoMechanicsFEM.h b/ProcessLib/ThermoMechanics/ThermoMechanicsFEM.h
index 144c113791a103048f721238399ecc05d13eb461..2197ea7c1b6972a606840390cb34815b82b172b7 100644
--- a/ProcessLib/ThermoMechanics/ThermoMechanicsFEM.h
+++ b/ProcessLib/ThermoMechanics/ThermoMechanicsFEM.h
@@ -87,7 +87,7 @@ struct SecondaryData
 template <typename ShapeFunction, typename IntegrationMethod,
           int DisplacementDim>
 class ThermoMechanicsLocalAssembler
-    : public ThermoMechanicsLocalAssemblerInterface
+    : public ThermoMechanicsLocalAssemblerInterface<DisplacementDim>
 {
 public:
     using ShapeMatricesType =
@@ -295,6 +295,14 @@ private:
 
     std::vector<double> getEpsilonMechanical() const override;
 
+    unsigned getNumberOfIntegrationPoints() const override;
+
+    typename MaterialLib::Solids::MechanicsBase<
+        DisplacementDim>::MaterialStateVariables const&
+    getMaterialStateVariablesAt(unsigned integration_point) const override;
+
+private:
+
     ThermoMechanicsProcessData<DisplacementDim>& _process_data;
 
     std::vector<
diff --git a/ProcessLib/ThermoMechanics/ThermoMechanicsProcess.cpp b/ProcessLib/ThermoMechanics/ThermoMechanicsProcess.cpp
index 5bba6a26d6e7718a2f281a6e10c19d4a624aaed2..477749f3a5cb92981fdba44f15e15bed2d9a7847 100644
--- a/ProcessLib/ThermoMechanics/ThermoMechanicsProcess.cpp
+++ b/ProcessLib/ThermoMechanics/ThermoMechanicsProcess.cpp
@@ -14,9 +14,9 @@
 
 #include "NumLib/DOF/ComputeSparsityPattern.h"
 #include "NumLib/DOF/DOFTableUtil.h"
+#include "ProcessLib/Deformation/SolidMaterialInternalToSecondaryVariables.h"
 #include "ProcessLib/Output/IntegrationPointWriter.h"
 #include "ProcessLib/SmallDeformation/CreateLocalAssemblers.h"
-
 #include "ThermoMechanicsFEM.h"
 
 namespace ProcessLib
@@ -178,21 +178,32 @@ void ThermoMechanicsProcess<DisplacementDim>::initializeConcreteProcess(
         mesh.getElements(), dof_table, _local_assemblers,
         mesh.isAxiallySymmetric(), integration_order, _process_data);
 
-    _secondary_variables.addSecondaryVariable(
-        "sigma",
-        makeExtrapolator(
-            MathLib::KelvinVector::KelvinVectorType<
-                DisplacementDim>::RowsAtCompileTime,
-            getExtrapolator(), _local_assemblers,
-            &ThermoMechanicsLocalAssemblerInterface::getIntPtSigma));
-
-    _secondary_variables.addSecondaryVariable(
-        "epsilon",
-        makeExtrapolator(
-            MathLib::KelvinVector::KelvinVectorType<
-                DisplacementDim>::RowsAtCompileTime,
-            getExtrapolator(), _local_assemblers,
-            &ThermoMechanicsLocalAssemblerInterface::getIntPtEpsilon));
+    auto add_secondary_variable = [&](std::string const& name,
+                                      int const num_components,
+                                      auto get_ip_values_function) {
+        _secondary_variables.addSecondaryVariable(
+            name,
+            makeExtrapolator(num_components, getExtrapolator(),
+                             _local_assemblers,
+                             std::move(get_ip_values_function)));
+    };
+
+    add_secondary_variable("sigma",
+                           MathLib::KelvinVector::KelvinVectorType<
+                               DisplacementDim>::RowsAtCompileTime,
+                           &LocalAssemblerInterface::getIntPtSigma);
+
+    add_secondary_variable("epsilon",
+                           MathLib::KelvinVector::KelvinVectorType<
+                               DisplacementDim>::RowsAtCompileTime,
+                           &LocalAssemblerInterface::getIntPtEpsilon);
+
+    //
+    // enable output of internal variables defined by material models
+    //
+    ProcessLib::Deformation::solidMaterialInternalToSecondaryVariables<
+        LocalAssemblerInterface>(_process_data.solid_materials,
+                                 add_secondary_variable);
 
     // Set initial conditions for integration point data.
     for (auto const& ip_writer : _integration_point_writer)
@@ -392,9 +403,9 @@ void ThermoMechanicsProcess<DisplacementDim>::preTimestepConcreteProcess(
     if (process_id == _process_data.mechanics_process_id)
     {
         GlobalExecutor::executeSelectedMemberOnDereferenced(
-            &ThermoMechanicsLocalAssemblerInterface::preTimestep,
-            _local_assemblers, pv.getActiveElementIDs(),
-            *_local_to_global_index_map, *x[process_id], t, dt);
+            &LocalAssemblerInterface::preTimestep, _local_assemblers,
+            pv.getActiveElementIDs(), *_local_to_global_index_map,
+            *x[process_id], t, dt);
         return;
     }
 
@@ -429,9 +440,9 @@ void ThermoMechanicsProcess<DisplacementDim>::postTimestepConcreteProcess(
     ProcessLib::ProcessVariable const& pv = getProcessVariables(process_id)[0];
 
     GlobalExecutor::executeSelectedMemberOnDereferenced(
-        &ThermoMechanicsLocalAssemblerInterface::postTimestep,
-        _local_assemblers, pv.getActiveElementIDs(),
-        *_local_to_global_index_map, *x[process_id], t, dt);
+        &LocalAssemblerInterface::postTimestep, _local_assemblers,
+        pv.getActiveElementIDs(), *_local_to_global_index_map, *x[process_id],
+        t, dt);
 }
 
 template <int DisplacementDim>
diff --git a/ProcessLib/ThermoMechanics/ThermoMechanicsProcess.h b/ProcessLib/ThermoMechanics/ThermoMechanicsProcess.h
index 9a7563b936706677b98ca35dd4cd820d0fb4552b..d4597f9cd58470125fb92ed3bec62105bf48f290 100644
--- a/ProcessLib/ThermoMechanics/ThermoMechanicsProcess.h
+++ b/ProcessLib/ThermoMechanics/ThermoMechanicsProcess.h
@@ -19,8 +19,6 @@ namespace ProcessLib
 {
 namespace ThermoMechanics
 {
-struct ThermoMechanicsLocalAssemblerInterface;
-
 template <int DisplacementDim>
 class ThermoMechanicsProcess final : public Process
 {
@@ -57,6 +55,9 @@ public:
         const int process_id) const override;
 
 private:
+    using LocalAssemblerInterface =
+        ThermoMechanicsLocalAssemblerInterface<DisplacementDim>;
+
     void constructDofTable() override;
 
     void initializeConcreteProcess(
@@ -91,8 +92,7 @@ private:
 private:
     ThermoMechanicsProcessData<DisplacementDim> _process_data;
 
-    std::vector<std::unique_ptr<ThermoMechanicsLocalAssemblerInterface>>
-        _local_assemblers;
+    std::vector<std::unique_ptr<LocalAssemblerInterface>> _local_assemblers;
 
     std::unique_ptr<NumLib::LocalToGlobalIndexMap>
         _local_to_global_index_map_single_component;