diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index b4fa54a..1b75600 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -1706,6 +1706,7 @@ class InlineModelAdmin(BaseModelAdmin):
     fk_name = None
     formset = BaseInlineFormSet
     extra = 3
+    min_num = None
     max_num = None
     template = None
     verbose_name = None
@@ -1738,6 +1739,10 @@ class InlineModelAdmin(BaseModelAdmin):
         """Hook for customizing the number of extra inline forms."""
         return self.extra
 
+    def get_min_num(self, request, obj=None, **kwargs):
+        """Hook for customizing the min number of inline forms."""
+        return self.min_num
+
     def get_max_num(self, request, obj=None, **kwargs):
         """Hook for customizing the max number of extra inline forms."""
         return self.max_num
@@ -1769,6 +1774,7 @@ class InlineModelAdmin(BaseModelAdmin):
             "exclude": exclude,
             "formfield_callback": partial(self.formfield_for_dbfield, request=request),
             "extra": self.get_extra(request, obj, **kwargs),
+            "min_num": self.get_min_num(request, obj, **kwargs),
             "max_num": self.get_max_num(request, obj, **kwargs),
             "can_delete": can_delete,
         }
diff --git a/django/contrib/contenttypes/admin.py b/django/contrib/contenttypes/admin.py
index c67fbca..9fa3af6 100644
--- a/django/contrib/contenttypes/admin.py
+++ b/django/contrib/contenttypes/admin.py
@@ -41,6 +41,7 @@ class GenericInlineModelAdmin(InlineModelAdmin):
             "can_delete": can_delete,
             "can_order": False,
             "fields": fields,
+            "min_num": self.min_num,
             "max_num": self.max_num,
             "exclude": exclude
         }
diff --git a/django/contrib/contenttypes/forms.py b/django/contrib/contenttypes/forms.py
index 33df752..f962793 100644
--- a/django/contrib/contenttypes/forms.py
+++ b/django/contrib/contenttypes/forms.py
@@ -56,9 +56,9 @@ def generic_inlineformset_factory(model, form=ModelForm,
                                   ct_field="content_type", fk_field="object_id",
                                   fields=None, exclude=None,
                                   extra=3, can_order=False, can_delete=True,
-                                  max_num=None,
-                                  formfield_callback=None, validate_max=False,
-                                  for_concrete_model=True):
+                                  max_num=None, validate_max=False,
+                                  min_num=None, validate_min=False,
+                                  formfield_callback=None, for_concrete_model=True):
     """
     Returns a ``GenericInlineFormSet`` for the given kwargs.
 
@@ -81,7 +81,8 @@ def generic_inlineformset_factory(model, form=ModelForm,
                                    formset=formset,
                                    extra=extra, can_delete=can_delete, can_order=can_order,
                                    fields=fields, exclude=exclude, max_num=max_num,
-                                   validate_max=validate_max)
+                                   validate_max=validate_max, min_num=min_num,
+                                   validate_min=validate_min)
     FormSet.ct_field = ct_field
     FormSet.ct_fk_field = fk_field
     FormSet.for_concrete_model = for_concrete_model
diff --git a/django/forms/models.py b/django/forms/models.py
index a0b47e6..b0a3c36 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -806,8 +806,8 @@ class BaseModelFormSet(BaseFormSet):
 
 def modelformset_factory(model, form=ModelForm, formfield_callback=None,
                          formset=BaseModelFormSet, extra=1, can_delete=False,
-                         can_order=False, max_num=None, fields=None, exclude=None,
-                         widgets=None, validate_max=False, localized_fields=None,
+                         can_order=False, min_num=None, max_num=None, fields=None,exclude=None,
+                         widgets=None, validate_min=False, validate_max=False, localized_fields=None,
                          labels=None, help_texts=None, error_messages=None):
     """
     Returns a FormSet class for the given Django model class.
@@ -831,9 +831,9 @@ def modelformset_factory(model, form=ModelForm, formfield_callback=None,
                              formfield_callback=formfield_callback,
                              widgets=widgets, localized_fields=localized_fields,
                              labels=labels, help_texts=help_texts, error_messages=error_messages)
-    FormSet = formset_factory(form, formset, extra=extra, max_num=max_num,
+    FormSet = formset_factory(form, formset, extra=extra, min_num=min_num, max_num=max_num,
                               can_order=can_order, can_delete=can_delete,
-                              validate_max=validate_max)
+                              validate_min=validate_min, validate_max=validate_max)
     FormSet.model = model
     return FormSet
 
@@ -975,8 +975,8 @@ def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False):
 def inlineformset_factory(parent_model, model, form=ModelForm,
                           formset=BaseInlineFormSet, fk_name=None,
                           fields=None, exclude=None, extra=3, can_order=False,
-                          can_delete=True, max_num=None, formfield_callback=None,
-                          widgets=None, validate_max=False, localized_fields=None,
+                          can_delete=True, min_num=None, max_num=None, formfield_callback=None,
+                          widgets=None, validate_min=False, validate_max=False, localized_fields=None,
                           labels=None, help_texts=None, error_messages=None):
     """
     Returns an ``InlineFormSet`` for the given kwargs.
@@ -997,8 +997,10 @@ def inlineformset_factory(parent_model, model, form=ModelForm,
         'can_order': can_order,
         'fields': fields,
         'exclude': exclude,
+        'min_num': min_num,
         'max_num': max_num,
         'widgets': widgets,
+        'validate_min': validate_min,
         'validate_max': validate_max,
         'localized_fields': localized_fields,
         'labels': labels,
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index e160926..63c1fa5 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -1993,6 +1993,18 @@ The ``InlineModelAdmin`` class adds:
     :meth:`InlineModelAdmin.get_max_num` also allows you to customize the
     maximum number of extra forms.
 
+    .. _ref-contrib-admin-inline-min-num:
+
+.. attribute:: InlineModelAdmin.min_num
+
+    This controls the minimum number of forms to show in the inline.
+    See :ref:`model-formsets-min-num` for more information.
+
+    .. versionadded:: 1.7
+
+    :meth:`InlineModelAdmin.get_min_num` also allows you to customize the
+    maximum number of extra forms.
+
 .. attribute:: InlineModelAdmin.raw_id_fields
 
     By default, Django's admin uses a select-box interface (<select>) for
@@ -2073,6 +2085,16 @@ The ``InlineModelAdmin`` class adds:
                     return max_num - 5
                 return max_num
 
+.. method:: InlineModelAdmin.get_min_num(request, obj=None, **kwargs)
+
+    .. versionadded:: 1.7
+
+    Returns the minimum number of inline forms to use. By default,
+    returns the :attr:`InlineModelAdmin.min_num` attribute.
+
+    Override this method to programmatically determine the minimum number of
+    inline forms. For example, this may be based on the model instance
+    (passed as the keyword argument ``obj``).
 
 Working with a model with two or more foreign keys to the same parent model
 ---------------------------------------------------------------------------
diff --git a/tests/admin_inlines/admin.py b/tests/admin_inlines/admin.py
index b46a045..a9ea346 100644
--- a/tests/admin_inlines/admin.py
+++ b/tests/admin_inlines/admin.py
@@ -8,7 +8,7 @@ from .models import (
     Inner4Tabular, NonAutoPKBook, Novel, ParentModelWithCustomPk, Poll,
     Profile, ProfileCollection, Question, ReadOnlyInline, ShoppingWeakness,
     Sighting, SomeChildModel, SomeParentModel, SottoCapo, Title,
-    TitleCollection,
+    TitleCollection, Holder5, Inner5
 )
 
 site = admin.AdminSite(name="admin")
@@ -171,6 +171,18 @@ class BinaryTreeAdmin(admin.TabularInline):
         return max_num
 
 
+# inline and admin for testing min_num
+
+class InnerMinNumInline(admin.TabularInline):
+    model = Inner5
+    min_num = 2
+    extra = 2
+
+
+class HolderMinNumAdmin(admin.ModelAdmin):
+    inlines = [InnerMinNumInline]
+
+
 # admin for #19524
 class SightingInline(admin.TabularInline):
     model = Sighting
@@ -212,3 +224,4 @@ site.register(ParentModelWithCustomPk, inlines=[ChildModel1Inline, ChildModel2In
 site.register(BinaryTree, inlines=[BinaryTreeAdmin])
 site.register(ExtraTerrestrial, inlines=[SightingInline])
 site.register(SomeParentModel, inlines=[SomeChildModelInline])
+site.register(Holder5, HolderMinNumAdmin)
diff --git a/tests/admin_inlines/models.py b/tests/admin_inlines/models.py
index 0ad59a0..b824728 100644
--- a/tests/admin_inlines/models.py
+++ b/tests/admin_inlines/models.py
@@ -114,6 +114,18 @@ class Inner4Tabular(models.Model):
     dummy = models.IntegerField(help_text="Awesome tabular help text is awesome.")
     holder = models.ForeignKey(Holder4)
 
+
+# Models for min_num
+
+class Holder5(models.Model):
+    dummy = models.IntegerField()
+
+
+class Inner5(models.Model):
+    dummy = models.IntegerField()
+    holder = models.ForeignKey(Holder5)
+
+
 # Models for #12749
 
 
diff --git a/tests/admin_inlines/tests.py b/tests/admin_inlines/tests.py
index 2f3fdfd..feb4225 100644
--- a/tests/admin_inlines/tests.py
+++ b/tests/admin_inlines/tests.py
@@ -221,6 +221,17 @@ class TestInline(TestCase):
         self.assertContains(response, max_forms_input % 2)
         self.assertContains(response, total_forms_hidden)
 
+    def test_min_num(self):
+        """
+        Ensure that min_num + extra dermine number of inlines.
+        """
+        min_forms = '<input id="id_inner5_set-MIN_NUM_FORMS" name="inner5_set-MIN_NUM_FORMS" type="hidden" value="2" />'
+        total_forms = '<input id="id_inner5_set-TOTAL_FORMS" name="inner5_set-TOTAL_FORMS" type="hidden" value="4" />'
+
+        response = self.client.get('/admin/admin_inlines/holder5/add/')
+        self.assertContains(response, min_forms)
+        self.assertContains(response, total_forms)
+
     def test_inline_nonauto_noneditable_pk(self):
         response = self.client.get('/admin/admin_inlines/author/add/')
         self.assertContains(response,
