diff --git a/dumux/assembly/cclocalassembler.hh b/dumux/assembly/cclocalassembler.hh
index 004bb7e8f09c4ce0c77f1afd1dad6c11d7e3f100..37e51257d379532d0b23debe41745d4af85c922d 100644
--- a/dumux/assembly/cclocalassembler.hh
+++ b/dumux/assembly/cclocalassembler.hh
@@ -63,8 +63,6 @@ class CCLocalAssemblerBase : public FVLocalAssemblerBase<TypeTag, Assembler, Imp
     using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView;
     using NumEqVector = GetPropType<TypeTag, Properties::NumEqVector>;
 
-    static_assert(!Assembler::Problem::enableInternalDirichletConstraints(), "Internal Dirichlet constraints are currently not implemented for cc-methods!");
-
 public:
 
     using ParentType::ParentType;
@@ -141,6 +139,7 @@ class CCLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/tru
     using FVElementGeometry = typename GridGeometry::LocalView;
     using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
     using JacobianMatrix = GetPropType<TypeTag, Properties::JacobianMatrix>;
+    using Problem = typename GridVariables::GridVolumeVariables::Problem;
 
     enum { numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq() };
     enum { dim = GetPropType<TypeTag, Properties::GridGeometry>::GridView::dimension };
@@ -275,15 +274,54 @@ public:
 
             // add the current partial derivatives to the global jacobian matrix
             // no special treatment is needed if globalJ is a ghost because then derivatives have been assembled to 0 above
-            for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
+            if constexpr (Problem::enableInternalDirichletConstraints())
             {
-                // the diagonal entries
-                A[globalI][globalI][eqIdx][pvIdx] += partialDerivs[0][eqIdx];
+                // check if own element has internal Dirichlet constraint
+                const auto internalDirichletConstraintsOwnElement = this->problem().hasInternalDirichletConstraint(this->element(), scv);
+                const auto dirichletValues = this->problem().internalDirichlet(this->element(), scv);
+
+                for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+                {
+                    if (internalDirichletConstraintsOwnElement[eqIdx])
+                    {
+                        origResiduals[0][eqIdx] = this->curElemVolVars()[scv].priVars()[eqIdx] - dirichletValues[eqIdx];
+                        A[globalI][globalI][eqIdx][pvIdx] = (eqIdx == pvIdx) ? 1.0 : 0.0;
+                    }
+                    else
+                        A[globalI][globalI][eqIdx][pvIdx] += partialDerivs[0][eqIdx];
+                }
 
                 // off-diagonal entries
                 j = 1;
                 for (const auto& dataJ : connectivityMap[globalI])
-                    A[dataJ.globalJ][globalI][eqIdx][pvIdx] += partialDerivs[j++][eqIdx];
+                {
+                    const auto& neighborElement = neighborElements[j-1];
+                    const auto& neighborScv = fvGeometry.scv(dataJ.globalJ);
+                    const auto internalDirichletConstraintsNeighbor = this->problem().hasInternalDirichletConstraint(neighborElement, neighborScv);
+
+                    for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+                    {
+                        if (internalDirichletConstraintsNeighbor[eqIdx])
+                            A[dataJ.globalJ][globalI][eqIdx][pvIdx] = 0.0;
+                        else
+                            A[dataJ.globalJ][globalI][eqIdx][pvIdx] += partialDerivs[j][eqIdx];
+                    }
+
+                    ++j;
+                }
+            }
+            else // no internal Dirichlet constraints specified
+            {
+                for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
+                {
+                    // the diagonal entries
+                    A[globalI][globalI][eqIdx][pvIdx] += partialDerivs[0][eqIdx];
+
+                    // off-diagonal entries
+                    j = 1;
+                    for (const auto& dataJ : connectivityMap[globalI])
+                        A[dataJ.globalJ][globalI][eqIdx][pvIdx] += partialDerivs[j++][eqIdx];
+                }
             }
 
             // restore the original state of the scv's volume variables
@@ -325,6 +363,7 @@ class CCLocalAssembler<TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/fal
     using Element = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView::template Codim<0>::Entity;
     using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
     using JacobianMatrix = GetPropType<TypeTag, Properties::JacobianMatrix>;
+    using Problem = typename GridVariables::GridVolumeVariables::Problem;
 
     enum { numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq() };
 
@@ -343,7 +382,7 @@ public:
             DUNE_THROW(Dune::InvalidStateException, "Using explicit jacobian assembler with stationary local residual");
 
         // assemble the undeflected residual
-        const auto residual = this->evalLocalResidual()[0];
+        auto residual = this->evalLocalResidual()[0];
         const auto storageResidual = this->evalLocalStorageResidual()[0];
 
         //////////////////////////////////////////////////////////////////////////////////////////////////
@@ -405,8 +444,28 @@ public:
 
             // add the current partial derivatives to the global jacobian matrix
             // only diagonal entries for explicit jacobians
-            for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
-                A[globalI][globalI][eqIdx][pvIdx] += partialDeriv[eqIdx];
+            if constexpr (Problem::enableInternalDirichletConstraints())
+            {
+                // check if own element has internal Dirichlet constraint
+                const auto internalDirichletConstraints = this->problem().hasInternalDirichletConstraint(this->element(), scv);
+                const auto dirichletValues = this->problem().internalDirichlet(this->element(), scv);
+
+                for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+                {
+                    if (internalDirichletConstraints[eqIdx])
+                    {
+                        residual[eqIdx] = this->curElemVolVars()[scv].priVars()[eqIdx] - dirichletValues[eqIdx];
+                        A[globalI][globalI][eqIdx][pvIdx] = (eqIdx == pvIdx) ? 1.0 : 0.0;
+                    }
+                    else
+                        A[globalI][globalI][eqIdx][pvIdx] += partialDeriv[eqIdx];
+                }
+            }
+            else
+            {
+                for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
+                    A[globalI][globalI][eqIdx][pvIdx] += partialDeriv[eqIdx];
+            }
 
             // restore the original state of the scv's volume variables
             curVolVars = origVolVars;
@@ -435,6 +494,7 @@ class CCLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/tr
     using NumEqVector = GetPropType<TypeTag, Properties::NumEqVector>;
     using JacobianMatrix = GetPropType<TypeTag, Properties::JacobianMatrix>;
     using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
+    using Problem = typename GridVariables::GridVolumeVariables::Problem;
 
     enum { numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq() };
 
@@ -461,7 +521,7 @@ public:
         }
 
         // assemble the undeflected residual
-        const auto residual = this->evalLocalResidual()[0];
+        auto residual = this->evalLocalResidual()[0];
 
         // get some aliases for convenience
         const auto& problem = this->problem();
@@ -507,6 +567,30 @@ public:
             }
         }
 
+        if constexpr (Problem::enableInternalDirichletConstraints())
+        {
+            // check if own element has internal Dirichlet constraint
+            const auto internalDirichletConstraints = this->problem().hasInternalDirichletConstraint(this->element(), scv);
+            const auto dirichletValues = this->problem().internalDirichlet(this->element(), scv);
+
+            for (int pvIdx = 0; pvIdx < numEq; ++pvIdx)
+            {
+                for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+                {
+                    if (internalDirichletConstraints[eqIdx])
+                    {
+                        residual[eqIdx] = this->curElemVolVars()[scv].priVars()[eqIdx] - dirichletValues[eqIdx];
+                        A[globalI][globalI][eqIdx][pvIdx] = (eqIdx == pvIdx) ? 1.0 : 0.0;
+
+                        // inner faces
+                        for (const auto& scvf : scvfs(fvGeometry))
+                            if (!scvf.boundary())
+                                A[globalI][fvGeometry.scv(scvf.outsideScvIdx()).dofIndex()][eqIdx][pvIdx] = 0.0;
+                    }
+                }
+            }
+        }
+
         // return element residual
         return residual;
     }
@@ -527,6 +611,7 @@ class CCLocalAssembler<TypeTag, Assembler, DiffMethod::analytic, /*implicit=*/fa
     using NumEqVector = GetPropType<TypeTag, Properties::NumEqVector>;
     using JacobianMatrix = GetPropType<TypeTag, Properties::JacobianMatrix>;
     using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
+    using Problem = typename GridVariables::GridVolumeVariables::Problem;
 
     enum { numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq() };
 
@@ -563,6 +648,25 @@ public:
         // add hand-code derivative of storage term
         this->localResidual().addStorageDerivatives(A[globalI][globalI], this->problem(), this->element(), this->fvGeometry(), volVars, scv);
 
+        if constexpr (Problem::enableInternalDirichletConstraints())
+        {
+            // check if own element has internal Dirichlet constraint
+            const auto internalDirichletConstraints = this->problem().hasInternalDirichletConstraint(this->element(), scv);
+            const auto dirichletValues = this->problem().internalDirichlet(this->element(), scv);
+
+            for (int pvIdx = 0; pvIdx < numEq; ++pvIdx)
+            {
+                for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+                {
+                    if (internalDirichletConstraints[eqIdx])
+                    {
+                        residual[eqIdx] = this->curElemVolVars()[scv].priVars()[eqIdx] - dirichletValues[eqIdx];
+                        A[globalI][globalI][eqIdx][pvIdx] = (eqIdx == pvIdx) ? 1.0 : 0.0;
+                    }
+                }
+            }
+        }
+
         // return the original residual
         return residual;
     }
diff --git a/dumux/assembly/fvlocalassemblerbase.hh b/dumux/assembly/fvlocalassemblerbase.hh
index 7d894ca276fce2b65e621189b2ad167908ed3bbd..5b77bb610671ad2d7cdb5be6e00f448e8b68fb81 100644
--- a/dumux/assembly/fvlocalassemblerbase.hh
+++ b/dumux/assembly/fvlocalassemblerbase.hh
@@ -221,12 +221,14 @@ public:
         // and set the residual to (privar - dirichletvalue)
         for (const auto& scvI : scvs(this->fvGeometry()))
         {
-            if (this->problem().hasInternalDirichletConstraint(this->element(), scvI))
+            const auto internalDirichletConstraints = this->problem().hasInternalDirichletConstraint(this->element(), scvI);
+            if (internalDirichletConstraints.any())
             {
                 const auto dirichletValues = this->problem().internalDirichlet(this->element(), scvI);
                 // set the Dirichlet conditions in residual and jacobian
-                for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
-                    applyDirichlet(scvI, dirichletValues, eqIdx, eqIdx);
+                for (int eqIdx = 0; eqIdx < internalDirichletConstraints.size(); ++eqIdx)
+                    if (internalDirichletConstraints[eqIdx])
+                        applyDirichlet(scvI, dirichletValues, eqIdx, eqIdx);
             }
         }
     }
diff --git a/dumux/multidomain/newtonsolver.hh b/dumux/multidomain/newtonsolver.hh
index 5d555124041799c3fcadaad06b72f36dba872df1..dba8c58a41b89b18c546275b1fb0fe29dda0235e 100644
--- a/dumux/multidomain/newtonsolver.hh
+++ b/dumux/multidomain/newtonsolver.hh
@@ -167,7 +167,7 @@ private:
         const auto& problem = this->assembler().problem(id);
         const auto& gridGeometry = this->assembler().gridGeometry(id);
         auto& gridVariables = this->assembler().gridVariables(id);
-        priVarSwitch.updateBoundary(problem, gridGeometry, gridVariables, sol[id]);
+        priVarSwitch.updateDirichletConstraints(problem, gridGeometry, gridVariables, sol[id]);
     }
 
     /*!
diff --git a/dumux/multidomain/subdomaincclocalassembler.hh b/dumux/multidomain/subdomaincclocalassembler.hh
index 60eb4e8ac4d718045b873f727b1ce93201b127db..a4657ac225a24e6c0027d334a28d44ba2d3095de 100644
--- a/dumux/multidomain/subdomaincclocalassembler.hh
+++ b/dumux/multidomain/subdomaincclocalassembler.hh
@@ -84,8 +84,6 @@ class SubDomainCCLocalAssemblerBase : public FVLocalAssemblerBase<TypeTag, Assem
     using CouplingManager = typename Assembler::CouplingManager;
     using ElementResidualVector = typename ParentType::LocalResidual::ElementResidualVector;
 
-    static_assert(!Problem::enableInternalDirichletConstraints(), "Internal Dirichlet constraints are currently not implemented for cc-methods!");
-
 public:
     //! export the domain id of this sub-domain
     static constexpr auto domainId = typename Dune::index_constant<id>();
@@ -282,6 +280,7 @@ class SubDomainCCLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*i
 {
     using ThisType = SubDomainCCLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*implicit=*/true>;
     using ParentType = SubDomainCCLocalAssemblerBase<id, TypeTag, Assembler, ThisType, /*implicit=*/true>;
+    using Problem = GetPropType<TypeTag, Properties::Problem>;
 
     using Scalar = GetPropType<TypeTag, Properties::Scalar>;
     using LocalResidualValues = GetPropType<TypeTag, Properties::NumEqVector>;
@@ -406,15 +405,54 @@ public:
                                                       eps_(elemSol[0][pvIdx], pvIdx), numDiffMethod);
 
             // add the current partial derivatives to the global jacobian matrix
-            for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
+            if constexpr (Problem::enableInternalDirichletConstraints())
             {
-                // the diagonal entries
-                A[globalI][globalI][eqIdx][pvIdx] += partialDerivs[0][eqIdx];
+                // check if own element has internal Dirichlet constraint
+                const auto internalDirichletConstraintsOwnElement = this->problem().hasInternalDirichletConstraint(this->element(), scv);
+                const auto dirichletValues = this->problem().internalDirichlet(this->element(), scv);
+
+                for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+                {
+                    if (internalDirichletConstraintsOwnElement[eqIdx])
+                    {
+                        origResiduals[0][eqIdx] = this->curElemVolVars()[scv].priVars()[eqIdx] - dirichletValues[eqIdx];
+                        A[globalI][globalI][eqIdx][pvIdx] = (eqIdx == pvIdx) ? 1.0 : 0.0;
+                    }
+                    else
+                        A[globalI][globalI][eqIdx][pvIdx] += partialDerivs[0][eqIdx];
+                }
 
                 // off-diagonal entries
                 j = 1;
                 for (const auto& dataJ : connectivityMap[globalI])
-                    A[dataJ.globalJ][globalI][eqIdx][pvIdx] += partialDerivs[j++][eqIdx];
+                {
+                    const auto& neighborElement = neighborElements[j-1];
+                    const auto& neighborScv = fvGeometry.scv(dataJ.globalJ);
+                    const auto internalDirichletConstraintsNeighbor = this->problem().hasInternalDirichletConstraint(neighborElement, neighborScv);
+
+                    for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+                    {
+                        if (internalDirichletConstraintsNeighbor[eqIdx])
+                            A[dataJ.globalJ][globalI][eqIdx][pvIdx] = 0.0;
+                        else
+                            A[dataJ.globalJ][globalI][eqIdx][pvIdx] += partialDerivs[j][eqIdx];
+                    }
+
+                    ++j;
+                }
+            }
+            else // no internal Dirichlet constraints specified
+            {
+                for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
+                {
+                    // the diagonal entries
+                    A[globalI][globalI][eqIdx][pvIdx] += partialDerivs[0][eqIdx];
+
+                    // off-diagonal entries
+                    j = 1;
+                    for (const auto& dataJ : connectivityMap[globalI])
+                        A[dataJ.globalJ][globalI][eqIdx][pvIdx] += partialDerivs[j++][eqIdx];
+                }
             }
 
             // restore the original state of the scv's volume variables
@@ -526,8 +564,31 @@ public:
                                                           epsCoupl(priVarsJ[pvIdx], pvIdx), numDiffMethod);
 
                 // add the current partial derivatives to the global jacobian matrix
-                for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
-                    A[globalI][globalJ][eqIdx][pvIdx] += partialDeriv[eqIdx];
+                if constexpr (Problem::enableInternalDirichletConstraints())
+                {
+                    const auto& scv = fvGeometry.scv(globalI);
+                    const auto internalDirichletConstraints = this->problem().hasInternalDirichletConstraint(this->element(), scv);
+                    if (internalDirichletConstraints.none())
+                    {
+                        for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
+                            A[globalI][globalJ][eqIdx][pvIdx] += partialDeriv[eqIdx];
+                    }
+                    else
+                    {
+                        for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+                        {
+                            if (internalDirichletConstraints[eqIdx])
+                                A[globalI][globalJ][eqIdx][pvIdx] = 0.0;
+                            else
+                                A[globalI][globalJ][eqIdx][pvIdx] += partialDeriv[eqIdx];
+                        }
+                    }
+                }
+                else
+                {
+                    for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
+                        A[globalI][globalJ][eqIdx][pvIdx] += partialDeriv[eqIdx];
+                }
 
                 // restore the current element solution
                 priVarsJ[pvIdx] = origPriVarsJ[pvIdx];
@@ -560,6 +621,7 @@ class SubDomainCCLocalAssembler<id, TypeTag, Assembler, DiffMethod::numeric, /*i
 
     using Scalar = GetPropType<TypeTag, Properties::Scalar>;
     using LocalResidualValues = GetPropType<TypeTag, Properties::NumEqVector>;
+    using Problem = GetPropType<TypeTag, Properties::Problem>;
 
     static constexpr int numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq();
     static constexpr auto domainI = Dune::index_constant<id>();
@@ -645,8 +707,28 @@ public:
 
             // add the current partial derivatives to the global jacobian matrix
             // only diagonal entries for explicit jacobians
-            for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
-                A[globalI][globalI][eqIdx][pvIdx] += partialDeriv[eqIdx];
+            if constexpr (Problem::enableInternalDirichletConstraints())
+            {
+                // check if own element has internal Dirichlet constraint
+                const auto internalDirichletConstraints = this->problem().hasInternalDirichletConstraint(this->element(), scv);
+                const auto dirichletValues = this->problem().internalDirichlet(this->element(), scv);
+
+                for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+                {
+                    if (internalDirichletConstraints[eqIdx])
+                    {
+                        residual[eqIdx] = this->curElemVolVars()[scv].priVars()[eqIdx] - dirichletValues[eqIdx];
+                        A[globalI][globalI][eqIdx][pvIdx] = (eqIdx == pvIdx) ? 1.0 : 0.0;
+                    }
+                    else
+                        A[globalI][globalI][eqIdx][pvIdx] += partialDeriv[eqIdx];
+                }
+            }
+            else
+            {
+                for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
+                    A[globalI][globalI][eqIdx][pvIdx] += partialDeriv[eqIdx];
+            }
 
             // restore the original state of the scv's volume variables
             curVolVars = origVolVars;
@@ -687,6 +769,7 @@ class SubDomainCCLocalAssembler<id, TypeTag, Assembler, DiffMethod::analytic, /*
     using LocalResidualValues = GetPropType<TypeTag, Properties::NumEqVector>;
     using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView;
     using Element = typename GridView::template Codim<0>::Entity;
+    using Problem = GetPropType<TypeTag, Properties::Problem>;
 
     enum { numEq = GetPropType<TypeTag, Properties::ModelTraits>::numEq() };
     enum { dim = GridView::dimension };
@@ -749,8 +832,35 @@ public:
             }
         }
 
-        // return element residual
-        return this->evalLocalResidual()[0];
+        if constexpr (Problem::enableInternalDirichletConstraints())
+        {
+            // check if own element has internal Dirichlet constraint
+            const auto internalDirichletConstraints = this->problem().hasInternalDirichletConstraint(this->element(), scv);
+            const auto dirichletValues = this->problem().internalDirichlet(this->element(), scv);
+
+            auto residual = this->evalLocalResidual()[0];
+
+            for (int pvIdx = 0; pvIdx < numEq; ++pvIdx)
+            {
+                for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+                {
+                    if (internalDirichletConstraints[eqIdx])
+                    {
+                        residual[eqIdx] = this->curElemVolVars()[scv].priVars()[eqIdx] - dirichletValues[eqIdx];
+                        A[globalI][globalI][eqIdx][pvIdx] = (eqIdx == pvIdx) ? 1.0 : 0.0;
+
+                        // inner faces
+                        for (const auto& scvf : scvfs(fvGeometry))
+                            if (!scvf.boundary())
+                                A[globalI][fvGeometry.scv(scvf.outsideScvIdx()).dofIndex()][eqIdx][pvIdx] = 0.0;
+                    }
+                }
+            }
+            return residual;
+        }
+        else
+            // return element residual
+            return this->evalLocalResidual()[0];
     }
 
     /*!
@@ -782,6 +892,20 @@ public:
         {
             const auto& elementJ = this->assembler().gridGeometry(domainJ).element(globalJ);
             this->couplingManager().addCouplingDerivatives(A[globalI][globalJ], domainI, element, fvGeometry, curElemVolVars, domainJ, elementJ);
+
+            // add the current partial derivatives to the global jacobian matrix
+            if constexpr (Problem::enableInternalDirichletConstraints())
+            {
+                const auto& scv = fvGeometry.scv(globalI);
+                const auto internalDirichletConstraints = this->problem().hasInternalDirichletConstraint(this->element(), scv);
+                if (internalDirichletConstraints.any())
+                {
+                    for (int pvIdx = 0; pvIdx < numEq; ++pvIdx)
+                        for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+                            if (internalDirichletConstraints[eqIdx])
+                                A[globalI][globalJ][eqIdx][pvIdx] = 0.0;
+                }
+            }
         }
     }
 };
diff --git a/dumux/nonlinear/newtonsolver.hh b/dumux/nonlinear/newtonsolver.hh
index 261d2434d61efef7792b0ed674ac1783dfd49e52..a5e34418f45e7692e4b1c29d1b803a05cbc78074 100644
--- a/dumux/nonlinear/newtonsolver.hh
+++ b/dumux/nonlinear/newtonsolver.hh
@@ -808,7 +808,7 @@ protected:
         const auto& problem = this->assembler().problem();
         const auto& gridGeometry = this->assembler().gridGeometry();
         auto& gridVariables = this->assembler().gridVariables();
-        priVarSwitch_->updateBoundary(problem, gridGeometry, gridVariables, sol);
+        priVarSwitch_->updateDirichletConstraints(problem, gridGeometry, gridVariables, sol);
     }
 
     /*!
diff --git a/dumux/porousmediumflow/compositional/primaryvariableswitch.hh b/dumux/porousmediumflow/compositional/primaryvariableswitch.hh
index 49cca272818914e00f886721773ec0ec4f3f9464..d6a02cda41f21fe6bf4d2946c7c3d34c7cb3ea43 100644
--- a/dumux/porousmediumflow/compositional/primaryvariableswitch.hh
+++ b/dumux/porousmediumflow/compositional/primaryvariableswitch.hh
@@ -203,15 +203,30 @@ public:
     /*!
      * \brief Updates the the primary variables state at the boundary.
      *
-     * Required when a Dirichlet BC differes from the initial conditon (only for box method).
+     * Required when a Dirichlet BC differs from the initial condition (only for box method).
      */
     template<class Problem, class GridVariables, class SolutionVector>
+    [[deprecated("Use updateDirichletConstraints() instead. Will be remove after 3.3")]]
     void updateBoundary(const Problem& problem,
                         const typename GridVariables::GridGeometry& gridGeometry,
                         GridVariables& gridVariables,
                         SolutionVector& sol)
     {
-        if constexpr (GridVariables::GridGeometry::discMethod == DiscretizationMethod::box)
+        updateDirichletConstraints(problem, gridGeometry, gridVariables, sol);
+    }
+
+    /*!
+     * \brief Updates the the primary variables state at the boundary.
+     *
+     * Required when a Dirichlet constraint (at a boundary or internal) differs from the initial condition.
+     */
+    template<class Problem, class GridVariables, class SolutionVector>
+    void updateDirichletConstraints(const Problem& problem,
+                                    const typename GridVariables::GridGeometry& gridGeometry,
+                                    GridVariables& gridVariables,
+                                    SolutionVector& sol)
+    {
+        if constexpr (GridVariables::GridGeometry::discMethod == DiscretizationMethod::box || Problem::enableInternalDirichletConstraints())
         {
             std::vector<bool> stateChanged(sol.size(), false);
             std::size_t countChanged = 0;
@@ -221,8 +236,8 @@ public:
                 auto fvGeometry = localView(gridGeometry);
                 fvGeometry.bindElement(element);
 
-                // skip if the element is not at a boundary
-                if (!fvGeometry.hasBoundaryScvf())
+                // skip if the element is not at a boundary or if no internal Dirichlet constraints are set
+                if (!Problem::enableInternalDirichletConstraints() && !fvGeometry.hasBoundaryScvf())
                     continue;
 
                 auto elemVolVars = localView(gridVariables.curGridVolVars());
@@ -230,40 +245,32 @@ public:
 
                 for (const auto& scv : scvs(fvGeometry))
                 {
-                    // this implies that state is set equal for all scvs associated with the dof
                     const auto dofIdx = scv.dofIndex();
-                    if (!gridGeometry.dofOnBoundary(dofIdx) || stateChanged[dofIdx])
+
+                    if (stateChanged[dofIdx])
                         continue;
 
-                    const auto bcTypes = problem.boundaryTypes(element, scv);
-                    if (bcTypes.hasDirichlet())
+                    if constexpr (GridVariables::GridGeometry::discMethod == DiscretizationMethod::box)
                     {
-                        const auto dirichletValues = problem.dirichlet(element, scv);
-
-                        if (sol[dofIdx].state() != dirichletValues.state())
+                        if (gridGeometry.dofOnBoundary(dofIdx))
                         {
-                            if (verbosity() > 1)
-                                std::cout << "Changing primary variable state at boundary (" << sol[dofIdx].state()
-                                          << ") to the one given by the Dirichlet condition (" << dirichletValues.state() << ") at dof " << dofIdx
-                                          << ", coordinates: " << scv.dofPosition()
-                                          << std::endl;
-
-                            // make sure the solution vector has the right state (given by the Dirichlet BC)
-                            sol[dofIdx].setState(dirichletValues.state());
-                            stateChanged[dofIdx] = true;
-                            ++countChanged;
-
-                            // overwrite initial with Dirichlet values
-                            for (int eqIdx = 0; eqIdx < SolutionVector::block_type::dimension; ++eqIdx)
+                            if (handleDirichletBoundaryCondition_(problem, element, scv, sol))
                             {
-                                if (bcTypes.isDirichlet(eqIdx))
-                                {
-                                    const auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
-                                    sol[dofIdx][pvIdx] = dirichletValues[pvIdx];
-                                }
+                                stateChanged[dofIdx] = true;
+                                ++countChanged;
+                                continue;
                             }
                         }
                     }
+
+                    if constexpr (Problem::enableInternalDirichletConstraints())
+                    {
+                        if (handleInternalDirichletConstraint_(problem, element, scv, sol))
+                        {
+                                stateChanged[dofIdx] = true;
+                                ++countChanged;
+                        }
+                    }
                 }
 
                 // update the volVars if caching is enabled
@@ -285,7 +292,7 @@ public:
             }
 
             if (verbosity_ > 0 && countChanged > 0)
-                std::cout << "Changed primary variable states and solution values at boundary to Dirichlet states and values at " << countChanged << " dof locations on processor "
+                std::cout << "Changed primary variable states and solution values to Dirichlet states and values at " << countChanged << " dof locations on processor "
                           << gridGeometry.gridView().comm().rank() << "." << std::endl;
         }
     }
@@ -338,10 +345,27 @@ protected:
                            const typename Geometry::SubControlVolume& scv,
                            const Problem& problem)
     {
-        if constexpr (Geometry::GridGeometry::discMethod != DiscretizationMethod::box)
+        // Dofs can be only constrained when using the Box method or when imposing internal Dirichlet constraints
+        if constexpr (Geometry::GridGeometry::discMethod != DiscretizationMethod::box && !Problem::enableInternalDirichletConstraints())
             return false;
 
-        else
+        // check for internally constrained Dofs
+        const auto isInternallyConstrainedDof = [&]()
+        {
+            if constexpr (!Problem::enableInternalDirichletConstraints())
+                return false;
+            else
+            {
+                const auto internalDirichletConstraints = problem.hasInternalDirichletConstraint(element, scv);
+                return internalDirichletConstraints.any();
+            }
+        };
+
+        if (isInternallyConstrainedDof())
+            return true;
+
+        // check for a Dirichlet BC when using the Box method
+        if constexpr (Geometry::GridGeometry::discMethod == DiscretizationMethod::box)
         {
             if (!fvGeometry.hasBoundaryScvf())
                 return false;
@@ -353,9 +377,87 @@ protected:
             const auto bcTypes = problem.boundaryTypes(element, scv);
             if (bcTypes.hasDirichlet())
                 return true;
+        }
 
-            return false;
+        return false;
+    }
+
+    template<class Problem, class Element, class SubControlVolume, class SolutionVector>
+    bool handleDirichletBoundaryCondition_(const Problem& problem,
+                                           const Element& element,
+                                           const SubControlVolume& scv,
+                                           SolutionVector& sol)
+    {
+        bool changed = false;
+        const auto bcTypes = problem.boundaryTypes(element, scv);
+        if (bcTypes.hasDirichlet())
+        {
+            const auto dirichletValues = problem.dirichlet(element, scv);
+            const auto dofIdx = scv.dofIndex();
+
+            if (sol[dofIdx].state() != dirichletValues.state())
+            {
+                if (verbosity() > 1)
+                    std::cout << "Changing primary variable state at boundary (" << sol[dofIdx].state()
+                                << ") to the one given by the Dirichlet condition (" << dirichletValues.state() << ") at dof " << dofIdx
+                                << ", coordinates: " << scv.dofPosition()
+                                << std::endl;
+
+                // make sure the solution vector has the right state (given by the Dirichlet BC)
+                sol[dofIdx].setState(dirichletValues.state());
+                changed = true;
+
+                // overwrite initial with Dirichlet values
+                for (int eqIdx = 0; eqIdx < SolutionVector::block_type::dimension; ++eqIdx)
+                {
+                    if (bcTypes.isDirichlet(eqIdx))
+                    {
+                        const auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
+                        sol[dofIdx][pvIdx] = dirichletValues[pvIdx];
+                    }
+                }
+            }
         }
+
+        return changed;
+    }
+
+    template<class Problem, class Element, class SubControlVolume, class SolutionVector>
+    bool handleInternalDirichletConstraint_(const Problem& problem,
+                                            const Element& element,
+                                            const SubControlVolume& scv,
+                                            SolutionVector& sol)
+    {
+        bool changed = false;
+
+        const auto internalDirichletConstraints = problem.hasInternalDirichletConstraint(element, scv);
+        if (internalDirichletConstraints.none())
+            return changed;
+
+        const auto dirichletValues = problem.internalDirichlet(element, scv);
+        const auto dofIdx = scv.dofIndex();
+
+        if (sol[dofIdx].state() != dirichletValues.state())
+        {
+            if (verbosity() > 1)
+                std::cout << "Changing primary variable state at internal DOF (" << sol[dofIdx].state()
+                            << ") to the one given by the internal Dirichlet constraint (" << dirichletValues.state() << ") at dof " << dofIdx
+                            << ", coordinates: " << scv.dofPosition()
+                            << std::endl;
+
+            // make sure the solution vector has the right state (given by the Dirichlet constraint)
+            sol[dofIdx].setState(dirichletValues.state());
+            changed = true;
+
+            // overwrite initial with Dirichlet values
+            for (int pvIdx = 0; pvIdx < SolutionVector::block_type::dimension; ++pvIdx)
+            {
+                if (internalDirichletConstraints[pvIdx])
+                    sol[dofIdx][pvIdx] = dirichletValues[pvIdx];
+            }
+        }
+
+        return changed;
     }
 
     std::vector<bool> wasSwitched_;
diff --git a/test/porousmediumflow/1p/implicit/internaldirichlet/CMakeLists.txt b/test/porousmediumflow/1p/implicit/internaldirichlet/CMakeLists.txt
index 1b5956b7acf5a1690686c32ad1eff2eb1df8f23f..a206bda3ea01d99e2651f8af9d287e2f6fb69a27 100644
--- a/test/porousmediumflow/1p/implicit/internaldirichlet/CMakeLists.txt
+++ b/test/porousmediumflow/1p/implicit/internaldirichlet/CMakeLists.txt
@@ -1,20 +1,14 @@
 
-# This feature (internal Dirichlet contraints) is currently not implemented for cc models
-# The compilation triggers a copmiler error (static_assert)
-# Once its implemented replace OnePInternalDirichletBox by OnePInternalDirichletTpfa (and uncomment OnePInternalDirichletTpfa in the problem.hh)
-#    and remove the EXPECT_COMPILE_FAIL flag
-
-# dumux_add_test(NAME test_1p_internaldirichlet_tpfa
-#               EXPECT_COMPILE_FAIL
-#               SOURCES ${CMAKE_SOURCE_DIR}/test/porousmediumflow/1p/implicit/incompressible/main.cc
-#               LABELS porousmediumflow 1p
-#               COMPILE_DEFINITIONS TYPETAG=OnePInternalDirichletTpfa
-#               COMPILE_DEFINITIONS NUMDIFFMETHOD=DiffMethod::analytic
-#               COMMAND ${CMAKE_SOURCE_DIR}/bin/testing/runtest.py
-#               CMD_ARGS  --script fuzzy
-#                         --files ${CMAKE_SOURCE_DIR}/test/references/test_1p_internaldirichlet_tpfa-reference.vtu
-#                                 ${CMAKE_CURRENT_BINARY_DIR}/test_1p_internaldirichlet_tpfa-00001.vtu
-#                         --command "${CMAKE_CURRENT_BINARY_DIR}/test_1p_internaldirichlet_tpfa ${CMAKE_SOURCE_DIR}/test/porousmediumflow/1p/implicit/incompressible/params.input -Problem.Name test_1p_internaldirichlet_tpfa -Problem.EnableGravity false")
+dumux_add_test(NAME test_1p_internaldirichlet_tpfa
+              SOURCES ${CMAKE_SOURCE_DIR}/test/porousmediumflow/1p/implicit/incompressible/main.cc
+              LABELS porousmediumflow 1p
+              COMPILE_DEFINITIONS TYPETAG=OnePInternalDirichletTpfa
+              COMPILE_DEFINITIONS NUMDIFFMETHOD=DiffMethod::analytic
+              COMMAND ${CMAKE_SOURCE_DIR}/bin/testing/runtest.py
+              CMD_ARGS  --script fuzzy
+                        --files ${CMAKE_SOURCE_DIR}/test/references/test_1p_internaldirichlet_tpfa-reference.vtu
+                                ${CMAKE_CURRENT_BINARY_DIR}/test_1p_internaldirichlet_tpfa-00001.vtu
+                        --command "${CMAKE_CURRENT_BINARY_DIR}/test_1p_internaldirichlet_tpfa ${CMAKE_SOURCE_DIR}/test/porousmediumflow/1p/implicit/incompressible/params.input -Problem.Name test_1p_internaldirichlet_tpfa -Problem.EnableGravity false")
 
 dumux_add_test(NAME test_1p_internaldirichlet_box
               SOURCES ${CMAKE_SOURCE_DIR}/test/porousmediumflow/1p/implicit/incompressible/main.cc
diff --git a/test/porousmediumflow/1p/implicit/internaldirichlet/problem.hh b/test/porousmediumflow/1p/implicit/internaldirichlet/problem.hh
index e87a9c4f1db916fa2846013cecb9a080c90d7d56..864c32b0e0c7db3c875d59e1840a72be71800066 100644
--- a/test/porousmediumflow/1p/implicit/internaldirichlet/problem.hh
+++ b/test/porousmediumflow/1p/implicit/internaldirichlet/problem.hh
@@ -25,6 +25,7 @@
 #ifndef DUMUX_INCOMPRESSIBLE_ONEP_TEST_PROBLEM_INTERNAL_DIRICHLET_HH
 #define DUMUX_INCOMPRESSIBLE_ONEP_TEST_PROBLEM_INTERNAL_DIRICHLET_HH
 
+#include <bitset>
 #include <dumux/common/boundarytypes.hh>
 #include <test/porousmediumflow/1p/implicit/incompressible/problem.hh>
 
@@ -36,8 +37,7 @@ namespace Properties {
 // Create new type tags
 namespace TTag {
 struct OnePInternalDirichlet {};
-// internal Dirichlet BC are currently not implemented for cc-models
-//struct OnePInternalDirichletTpfa { using InheritsFrom = std::tuple<OnePInternalDirichlet, OnePIncompressibleTpfa>; };
+struct OnePInternalDirichletTpfa { using InheritsFrom = std::tuple<OnePInternalDirichlet, OnePIncompressibleTpfa>; };
 struct OnePInternalDirichletBox { using InheritsFrom = std::tuple<OnePInternalDirichlet, OnePIncompressibleBox>; };
 } // end namespace TTag
 
@@ -61,11 +61,15 @@ class OnePTestProblemInternalDirichlet : public OnePTestProblem<TypeTag>
     using Scalar = GetPropType<TypeTag, Properties::Scalar>;
     using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
     using NeumannValues = GetPropType<TypeTag, Properties::NumEqVector>;
-    using BoundaryTypes = Dumux::BoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>;
+    using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
+    using BoundaryTypes = Dumux::BoundaryTypes<ModelTraits::numEq()>;
+    using Indices = typename ModelTraits::Indices;
     using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
     using SubControlVolume = typename GridGeometry::SubControlVolume;
     using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
 
+    static constexpr auto numEq = ModelTraits::numEq();
+
 public:
     OnePTestProblemInternalDirichlet(std::shared_ptr<const GridGeometry> gridGeometry)
     : ParentType(gridGeometry)
@@ -118,11 +122,15 @@ public:
      * \param element The finite element
      * \param scv The sub-control volume
      */
-    bool hasInternalDirichletConstraint(const Element& element, const SubControlVolume& scv) const
+    std::bitset<numEq> hasInternalDirichletConstraint(const Element& element,
+                                                      const SubControlVolume& scv) const
     {
         // the pure Neumann problem is only defined up to a constant
         // we create a well-posed problem by fixing the pressure at one dof in the middle of the domain
-        return (scv.dofIndex() == static_cast<std::size_t>(this->gridGeometry().numDofs()/2));
+        std::bitset<numEq> values;
+        if (scv.dofIndex() == static_cast<std::size_t>(this->gridGeometry().numDofs()/2))
+            values.set(Indices::pressureIdx);
+        return values;
     }
 
     /*!