diff --git a/dumux/common/staggeredfvproblem.hh b/dumux/common/staggeredfvproblem.hh
index c66515c0f607e1e2f2b138d778f4c9cd99722301..a517417d81c0234901f11337bf1668effe789188 100644
--- a/dumux/common/staggeredfvproblem.hh
+++ b/dumux/common/staggeredfvproblem.hh
@@ -53,6 +53,13 @@ class StaggeredFVProblem : public FVProblem<TypeTag>
     using Implementation = typename GET_PROP_TYPE(TypeTag, Problem);
     using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
     using Element = typename GridView::template Codim<0>::Entity;
+
+    using GridVariables = typename GET_PROP_TYPE(TypeTag, GridVariables);
+    using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
+    using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
+    using GridFaceVariables = typename GridVariables::GridFaceVariables;
+    using ElementFaceVariables = typename GridFaceVariables::LocalView;
+
     using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
     using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
     using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector);
@@ -106,6 +113,28 @@ public:
         return asImp_().sourceAtPos(e.center());
     }
 
+    /*!
+     * \brief Evaluate the boundary conditions for a neumann
+     *        boundary segment.
+     *
+     * This is the method for the case where the Neumann condition is
+     * potentially solution dependent
+     * \param elemFaceVars All face variables for the element
+     * \param scvf The sub control volume face
+     *
+     * Negative values mean influx.
+     * E.g. for the mass balance that would the mass flux in \f$ [ kg / (m^2 \cdot s)] \f$.
+     */
+    NumEqVector neumann(const Element& element,
+                        const FVElementGeometry& fvGeometry,
+                        const ElementVolumeVariables& elemVolVars,
+                        const ElementFaceVariables& elemFaceVars,
+                        const SubControlVolumeFace& scvf) const
+    {
+        // forward it to the interface with only the global position
+        return asImp_().neumannAtPos(scvf.ipGlobal());
+    }
+
     /*!
      * \brief Evaluate the initial value for a control volume.
      *
diff --git a/dumux/discretization/staggered/freeflow/subcontrolvolumeface.hh b/dumux/discretization/staggered/freeflow/subcontrolvolumeface.hh
index 426657563cfc9ce92f8fac15456551a3391028f9..bc1c61fddd6a26444f168552b33434f9a7b3d035 100644
--- a/dumux/discretization/staggered/freeflow/subcontrolvolumeface.hh
+++ b/dumux/discretization/staggered/freeflow/subcontrolvolumeface.hh
@@ -100,11 +100,13 @@ public:
     //! Constructor for a ghost face outside of the domain. Only needed to retrieve the center and scvIndices
     FreeFlowStaggeredSubControlVolumeFace(const GlobalPosition& dofPosition,
                                           const std::vector<GridIndexType>& scvIndices,
-                                          const int dofIdx = -1)
+                                          const int dofIdx = -1,
+                                          const int scvfIndex = -1)
     : center_(dofPosition),
-      scvfIndex_(-1),
+      scvfIndex_(scvfIndex),
       scvIndices_(scvIndices),
       dofIdx_(dofIdx),
+      selfToOppositeDistance_(0.0),
       isGhostFace_(true)
     {}
 
diff --git a/dumux/freeflow/navierstokes/staggered/fluxvariables.hh b/dumux/freeflow/navierstokes/staggered/fluxvariables.hh
index 996bf049b2e75d090287fc194c2d2cfb5f007f45..5780abd862d1d06b90981f8321dd506dc0cfe53c 100644
--- a/dumux/freeflow/navierstokes/staggered/fluxvariables.hh
+++ b/dumux/freeflow/navierstokes/staggered/fluxvariables.hh
@@ -272,7 +272,7 @@ public:
     *                scvf
     *              ---------#######                 || and # staggered half-control-volume
     *              |      ||      | current scvf
-    *              |      ||      |                 # normal staggered faces over wich fluxes are calculated
+    *              |      ||      |                 # normal staggered sub faces over wich fluxes are calculated
     *              |      ||      x~~~~> vel.Self
     *              |      ||      |                 x dof position
     *        scvf  |      ||      |
@@ -291,22 +291,43 @@ public:
         auto& faceVars = elemFaceVars[scvf];
         const int numSubFaces = scvf.pairData().size();
 
-        // Account for all sub-faces.
+        // Account for all sub faces.
         for(int localSubFaceIdx = 0; localSubFaceIdx < numSubFaces; ++localSubFaceIdx)
         {
             const auto eIdx = scvf.insideScvIdx();
+            // Get the face normal to the face the dof lives on. The staggered sub face conincides with half of this normal face.
             const auto& normalFace = fvGeometry.scvf(eIdx, scvf.pairData()[localSubFaceIdx].localNormalFaceIdx);
 
-            // Check if we have a symmetry boundary condition. If yes, the tangental part of the momentum flux can be neglected.
+            // Check if there is face/element parallel to our face of interest where the dof lives on. If there is no parallel neighbor,
+            // we are on a boundary where we have to check for boundary conditions.
             if(!scvf.hasParallelNeighbor(localSubFaceIdx))
             {
-                // Use the ghost face to check if there is a symmetry boundary condition and skip any further steps if yes.
-                const auto bcTypes = problem.boundaryTypes(element, makeParallelGhostFace_(scvf, localSubFaceIdx));
+                // Construct a temporary scvf which corresponds to the staggered sub face, featuring the location
+                // the sub faces's center.
+                auto localSubFaceCenter = scvf.pairData(localSubFaceIdx).virtualOuterParallelFaceDofPos - normalFace.center();
+                localSubFaceCenter *= 0.5;
+                localSubFaceCenter += normalFace.center();
+                const auto localSubFace = makeGhostFace_(normalFace, localSubFaceCenter);
+
+                // Retrieve the boundary types that correspond to the sub face.
+                const auto bcTypes = problem.boundaryTypes(element, localSubFace);
+
+                // Check if we have a symmetry boundary condition. If yes, the tangental part of the momentum flux can be neglected
+                // and we may skip any further calculations for the given sub face.
                 if(bcTypes.isSymmetry())
                     continue;
+
+                // Handle Neumann boundary conditions. No further calculations are then required for the given sub face.
+                if(bcTypes.isNeumann(Indices::velocity(scvf.directionIndex())))
+                {
+                    const auto extrusionFactor = elemVolVars[normalFace.insideScvIdx()].extrusionFactor();
+                    normalFlux += problem.neumann(element, fvGeometry, elemVolVars, elemFaceVars, localSubFace)[Indices::velocity(scvf.directionIndex())]
+                                                  * extrusionFactor * normalFace.area() * 0.5;
+                    continue;
+                }
             }
 
-            // If there is no symmetry boundary condition, proceed to calculate the tangential momentum flux.
+            // If there is no symmetry or Neumann boundary condition for the given sub face, proceed to calculate the tangential momentum flux.
             if(enableInertiaTerms)
                 normalFlux += computeAdvectivePartOfNormalMomentumFlux_(problem, element, scvf, normalFace, elemVolVars, faceVars, localSubFaceIdx);
 
@@ -541,19 +562,19 @@ private:
 
 private:
 
-    //! helper functiuob to conveniently create a ghost face which is outside the domain, parallel to the scvf of interest
+    //! helper function to conveniently create a ghost face used to retrieve boundary values from the problem
     SubControlVolumeFace makeGhostFace_(const SubControlVolumeFace& ownScvf, const GlobalPosition& pos) const
     {
-        return SubControlVolumeFace(pos, std::vector<unsigned int>{ownScvf.insideScvIdx(), ownScvf.outsideScvIdx()}, ownScvf.dofIndex());
+        return SubControlVolumeFace(pos, std::vector<unsigned int>{ownScvf.insideScvIdx(), ownScvf.outsideScvIdx()}, ownScvf.dofIndex(), ownScvf.index());
     };
 
-    //! helper functiuob to conveniently create a ghost face which is outside the domain, parallel to the scvf of interest
+    //! helper function to conveniently create a ghost face which is outside the domain, normal to the scvf of interest
     SubControlVolumeFace makeNormalGhostFace_(const SubControlVolumeFace& ownScvf, const int localSubFaceIdx) const
     {
         return makeGhostFace_(ownScvf, ownScvf.pairData(localSubFaceIdx).virtualOuterNormalFaceDofPos);
     };
 
-    //! helper functiuob to conveniently create a ghost face which is outside the domain, parallel to the scvf of interest
+    //! helper function to conveniently create a ghost face which is outside the domain, parallel to the scvf of interest
     SubControlVolumeFace makeParallelGhostFace_(const SubControlVolumeFace& ownScvf, const int localSubFaceIdx) const
     {
         return makeGhostFace_(ownScvf, ownScvf.pairData(localSubFaceIdx).virtualOuterParallelFaceDofPos);
diff --git a/dumux/freeflow/navierstokes/staggered/localresidual.hh b/dumux/freeflow/navierstokes/staggered/localresidual.hh
index 9c1c37a7fe86a5da12d47d30b4ac21c19eb29daf..7ef4336a84df321e2a90f91a02b915c4c68cec91 100644
--- a/dumux/freeflow/navierstokes/staggered/localresidual.hh
+++ b/dumux/freeflow/navierstokes/staggered/localresidual.hh
@@ -233,8 +233,8 @@ protected:
                     {
                         if(bcTypes.isNeumann(eqIdx + cellCenterOffset))
                         {
-                            const auto extrusionFactor = 1.0; //TODO: get correct extrusion factor
-                            boundaryFlux[eqIdx] = problem.neumann(element, fvGeometry, elemVolVars, scvf)[eqIdx + cellCenterOffset]
+                            const auto extrusionFactor = elemVolVars[scvf.insideScvIdx()].extrusionFactor();
+                            boundaryFlux[eqIdx] = problem.neumann(element, fvGeometry, elemVolVars, elemFaceVars, scvf)[eqIdx + cellCenterOffset]
                                                   * extrusionFactor * scvf.area();
                         }
                     }
@@ -293,11 +293,23 @@ protected:
                 residual = velocity - dirichletValue;
             }
 
+            // handle Neumann boundary conditions
+            if(bcTypes.isNeumann(Indices::velocity(scvf.directionIndex())))
+            {
+                // set the given Neumann flux for the face on the boundary itself
+                const auto extrusionFactor = elemVolVars[scvf.insideScvIdx()].extrusionFactor();
+                residual = problem.neumann(element, fvGeometry, elemVolVars, elementFaceVars, scvf)[Indices::velocity(scvf.directionIndex())]
+                                           * extrusionFactor * scvf.area();
+
+                // treat the remaining (normal) faces of the staggered control volume
+                FluxVariables fluxVars;
+                residual += fluxVars.computeNormalMomentumFlux(problem, element, scvf, fvGeometry, elemVolVars, elementFaceVars);
+            }
+
             // For symmetry boundary conditions, there is no flow accross the boundary and
             // we therefore treat it like a Dirichlet boundary conditions with zero velocity
             if(bcTypes.isSymmetry())
             {
-                // const Scalar velocity = faceVars.faceVars(scvf.dofIndex()).velocity();
                 const Scalar velocity = elementFaceVars[scvf].velocitySelf();
                 const Scalar fixedValue = 0.0;
                 residual = velocity - fixedValue;