diff --git a/hypha/apply/funds/migrations/0100_alter_applicationbase_labbase_approval_form.py b/hypha/apply/funds/migrations/0100_alter_applicationbase_labbase_approval_form.py
new file mode 100644
index 0000000000000000000000000000000000000000..dd958a461b0b8f9b9443efe656621f30a5d90274
--- /dev/null
+++ b/hypha/apply/funds/migrations/0100_alter_applicationbase_labbase_approval_form.py
@@ -0,0 +1,25 @@
+# Generated by Django 3.2.13 on 2022-07-08 11:28
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('application_projects', '0053_projectapprovalform'),
+        ('funds', '0099_auto_20220629_1339'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='applicationbase',
+            name='approval_form',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='funds', to='application_projects.projectapprovalform'),
+        ),
+        migrations.AddField(
+            model_name='labbase',
+            name='approval_form',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='labs', to='application_projects.projectapprovalform'),
+        ),
+    ]
diff --git a/hypha/apply/funds/models/applications.py b/hypha/apply/funds/models/applications.py
index ef24ed5599e23b91357338a0fc0f383fd2ee7c9e..13837638bc5b5e5d94837eeab6297f921f8ee35b 100644
--- a/hypha/apply/funds/models/applications.py
+++ b/hypha/apply/funds/models/applications.py
@@ -71,6 +71,14 @@ class ApplicationBase(EmailForm, WorkflowStreamForm):  # type: ignore
         blank=True,
     )
 
+    approval_form = models.ForeignKey(
+        'application_projects.ProjectApprovalForm',
+        blank=True,
+        null=True,
+        on_delete=models.SET_NULL,
+        related_name='funds',
+    )
+
     guide_link = models.URLField(blank=True, max_length=255, help_text=_('Link to the apply guide.'))
 
     slack_channel = models.CharField(blank=True, max_length=128, help_text=_('The slack #channel for notifications. If left empty, notifications will go to the default channel.'))
@@ -108,6 +116,7 @@ class ApplicationBase(EmailForm, WorkflowStreamForm):  # type: ignore
         return self.open_round.serve(request)
 
     content_panels = WorkflowStreamForm.content_panels + [
+        FieldPanel('approval_form'),
         FieldPanel('reviewers', widget=forms.SelectMultiple(attrs={'size': '16'})),
         FieldPanel('guide_link'),
         FieldPanel('slack_channel'),
@@ -409,6 +418,14 @@ class LabBase(EmailForm, WorkflowStreamForm, SubmittableStreamForm):  # type: ig
         blank=True,
     )
 
+    approval_form = models.ForeignKey(
+        'application_projects.ProjectApprovalForm',
+        blank=True,
+        null=True,
+        on_delete=models.SET_NULL,
+        related_name='labs',
+    )
+
     guide_link = models.URLField(blank=True, max_length=255, help_text=_('Link to the apply guide.'))
 
     slack_channel = models.CharField(blank=True, max_length=128, help_text=_('The slack #channel for notifications.'))
@@ -417,6 +434,7 @@ class LabBase(EmailForm, WorkflowStreamForm, SubmittableStreamForm):  # type: ig
     subpage_types = []  # type: ignore
 
     content_panels = WorkflowStreamForm.content_panels + [
+        FieldPanel('approval_form'),
         FieldPanel('lead'),
         FieldPanel('reviewers', widget=forms.SelectMultiple(attrs={'size': '16'})),
         FieldPanel('guide_link'),
diff --git a/hypha/apply/funds/tests/factories/models.py b/hypha/apply/funds/tests/factories/models.py
index 9da35a9b8fbf14a428183e84ddfc1036d963ee95..59727aa6127e314069bd332d97b752d419ba12fa 100644
--- a/hypha/apply/funds/tests/factories/models.py
+++ b/hypha/apply/funds/tests/factories/models.py
@@ -82,6 +82,7 @@ class AbstractApplicationFactory(wagtail_factories.PageFactory):
 
     # Will need to update how the stages are identified as Fund Page changes
     workflow_name = factory.LazyAttribute(lambda o: workflow_for_stages(o.workflow_stages))
+    approval_form = factory.SubFactory('hypha.apply.projects.tests.factories.ProjectApprovalFormFactory')
 
     @factory.post_generation
     def forms(self, create, extracted, **kwargs):
diff --git a/hypha/apply/funds/tests/test_admin_form.py b/hypha/apply/funds/tests/test_admin_form.py
index 80119563409e97f5ae1f4c905c22da621af7579d..d90622fe487b524c23307f7d44f2c1ee8760ba97 100644
--- a/hypha/apply/funds/tests/test_admin_form.py
+++ b/hypha/apply/funds/tests/test_admin_form.py
@@ -54,6 +54,7 @@ def form_data(num_appl_forms=0, num_review_forms=0, num_determination_forms=0, n
     fund_data['workflow_name'] = workflow_for_stages(stages)
 
     form_data.update(fund_data)
+    form_data.update(approval_form='')
     return form_data
 
 
diff --git a/hypha/apply/projects/admin.py b/hypha/apply/projects/admin.py
index 711563188a21bdd91c2e29ea110956626a556f9e..2192a905029d65670e97d25449ee6d72694fc0f6 100644
--- a/hypha/apply/projects/admin.py
+++ b/hypha/apply/projects/admin.py
@@ -1,6 +1,7 @@
 from wagtail.contrib.modeladmin.options import ModelAdmin, ModelAdminGroup
 
-from .models import DocumentCategory
+from .admin_views import CreateProjectApprovalFormView, EditProjectApprovalFormView
+from .models import DocumentCategory, ProjectApprovalForm
 
 
 class DocumentCategoryAdmin(ModelAdmin):
@@ -9,9 +10,26 @@ class DocumentCategoryAdmin(ModelAdmin):
     list_display = ('name', 'recommended_minimum',)
 
 
+class ProjectApprovalFormAdmin(ModelAdmin):
+    model = ProjectApprovalForm
+    menu_icon = 'form'
+    list_display = ('name', 'used_by',)
+    create_view_class = CreateProjectApprovalFormView
+    edit_view_class = EditProjectApprovalFormView
+
+    def used_by(self, obj):
+        rows = list()
+        for field in ('funds', 'labs',):
+            related = ', '.join(getattr(obj, f'{field}').values_list('title', flat=True))
+            if related:
+                rows.append(related)
+        return ', '.join(rows)
+
+
 class ManageAdminGoup(ModelAdminGroup):
     menu_label = 'Manage'
     menu_icon = 'folder-open-inverse'
     items = (
         DocumentCategoryAdmin,
+        ProjectApprovalFormAdmin,
     )
diff --git a/hypha/apply/projects/admin_views.py b/hypha/apply/projects/admin_views.py
new file mode 100644
index 0000000000000000000000000000000000000000..1356717a7dd9f23fbb58361f67080391c709532c
--- /dev/null
+++ b/hypha/apply/projects/admin_views.py
@@ -0,0 +1,37 @@
+from wagtail.contrib.modeladmin.views import CreateView, EditView
+
+from hypha.apply.utils.blocks import show_admin_form_error_messages
+
+
+class CreateProjectApprovalFormView(CreateView):
+
+    def get_form(self):
+        """
+        Overriding this method to disable the single file block option from Project Approval Form.
+        Set 0 as max_number of single file can be added to make single file block option unavailable or disable.
+        """
+        form = super(CreateProjectApprovalFormView, self).get_form()
+        form.fields['form_fields'].block.meta.block_counts = {'file': {'min_num': 0, 'max_num': 0}}
+        return form
+
+    def form_invalid(self, form):
+        show_admin_form_error_messages(self.request, form)
+        return self.render_to_response(self.get_context_data(form=form))
+
+
+class EditProjectApprovalFormView(EditView):
+
+    def get_form(self):
+        """
+        Overriding this method to disable the single file block option from Project Approval Form.
+        Calculating the number of Single file blocks that exist in the instance already.
+        And set that count as max_number of single file block can be added to make single file option disable.
+        """
+        form = super(EditProjectApprovalFormView, self).get_form()
+        single_file_count = sum(1 for block in self.get_instance().form_fields.raw_data if block['type'] == 'file')
+        form.fields['form_fields'].block.meta.block_counts = {'file': {'min_num': 0, 'max_num': single_file_count}}
+        return form
+
+    def form_invalid(self, form):
+        show_admin_form_error_messages(self.request, form)
+        return self.render_to_response(self.get_context_data(form=form))
diff --git a/hypha/apply/projects/forms/project.py b/hypha/apply/projects/forms/project.py
index 7e0da4777bf2d0825fab2523746984f1a4caff3e..c7e3e2c7329481f3d62d8bd5bcd14e564e5bc41d 100644
--- a/hypha/apply/projects/forms/project.py
+++ b/hypha/apply/projects/forms/project.py
@@ -4,6 +4,7 @@ from django.db.models import Q
 from django.utils.translation import gettext_lazy as _
 
 from hypha.apply.funds.models import ApplicationSubmission
+from hypha.apply.stream_forms.forms import StreamBaseForm
 from hypha.apply.users.groups import STAFF_GROUP_NAME
 
 from ..models.project import COMMITTED, Approval, Contract, PacketFile, Project
@@ -76,30 +77,38 @@ class CreateApprovalForm(forms.ModelForm):
         return by
 
 
-class ProjectApprovalForm(forms.ModelForm):
+class MixedMetaClass(type(StreamBaseForm), type(forms.ModelForm)):
+    pass
+
+
+class ProjectApprovalForm(StreamBaseForm, forms.ModelForm, metaclass=MixedMetaClass):
     class Meta:
         fields = [
             'title',
-            'value',
-            'proposed_start',
-            'proposed_end',
         ]
         model = Project
         widgets = {
-            'title': forms.TextInput,
-            'proposed_end': forms.DateInput,
-            'proposed_start': forms.DateInput,
+            'title': forms.HiddenInput()
         }
 
     def __init__(self, *args, extra_fields=None, **kwargs):
         super().__init__(*args, **kwargs)
-        if extra_fields:
-            self.fields = {
-                **self.fields,
-                **extra_fields,
-            }
+
+    def clean(self):
+        cleaned_data = super().clean()
+        cleaned_data['form_data'] = {
+            key: value
+            for key, value in cleaned_data.items()
+            if key not in self._meta.fields
+        }
+        return cleaned_data
 
     def save(self, *args, **kwargs):
+        self.instance.form_data = {
+            field: self.cleaned_data[field]
+            for field in self.instance.question_field_ids
+            if field in self.cleaned_data
+        }
         self.instance.user_has_updated_details = True
         return super().save(*args, **kwargs)
 
diff --git a/hypha/apply/projects/migrations/0053_projectapprovalform.py b/hypha/apply/projects/migrations/0053_projectapprovalform.py
new file mode 100644
index 0000000000000000000000000000000000000000..6b5d8c4887a61ce0514773c01a83c958af686888
--- /dev/null
+++ b/hypha/apply/projects/migrations/0053_projectapprovalform.py
@@ -0,0 +1,26 @@
+# Generated by Django 3.2.13 on 2022-07-08 11:28
+
+from django.db import migrations, models
+import hypha.apply.stream_forms.blocks
+import hypha.apply.stream_forms.models
+import wagtail.core.blocks
+import wagtail.core.fields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('application_projects', '0052_alter_project_form_fields'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ProjectApprovalForm',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=255)),
+                ('form_fields', wagtail.core.fields.StreamField([('text_markup', wagtail.core.blocks.RichTextBlock(group='Custom', label='Section text')), ('header_markup', wagtail.core.blocks.StructBlock([('heading_text', wagtail.core.blocks.CharBlock(form_classname='title', required=True)), ('size', wagtail.core.blocks.ChoiceBlock(choices=[('h2', 'H2'), ('h3', 'H3'), ('h4', 'H4')]))], group='Custom', label='Section header')), ('char', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('format', wagtail.core.blocks.ChoiceBlock(choices=[('email', 'Email'), ('url', 'URL')], label='Format', required=False)), ('default_value', wagtail.core.blocks.CharBlock(label='Default value', required=False))], group='Fields')), ('multi_inputs_char', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('format', wagtail.core.blocks.ChoiceBlock(choices=[('email', 'Email'), ('url', 'URL')], label='Format', required=False)), ('default_value', wagtail.core.blocks.CharBlock(label='Default value', required=False)), ('number_of_inputs', wagtail.core.blocks.IntegerBlock(default=2, label='Max number of inputs')), ('add_button_text', wagtail.core.blocks.CharBlock(default='Add new item', required=False))], group='Fields')), ('text', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.TextBlock(label='Default value', required=False)), ('word_limit', wagtail.core.blocks.IntegerBlock(default=1000, label='Word limit'))], group='Fields')), ('number', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.CharBlock(label='Default value', required=False))], group='Fields')), ('checkbox', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.BooleanBlock(required=False))], group='Fields')), ('radios', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('choices', wagtail.core.blocks.ListBlock(wagtail.core.blocks.CharBlock(label='Choice')))], group='Fields')), ('dropdown', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('choices', wagtail.core.blocks.ListBlock(wagtail.core.blocks.CharBlock(label='Choice')))], group='Fields')), ('checkboxes', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('checkboxes', wagtail.core.blocks.ListBlock(wagtail.core.blocks.CharBlock(label='Checkbox')))], group='Fields')), ('date', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.DateBlock(required=False))], group='Fields')), ('time', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.TimeBlock(required=False))], group='Fields')), ('datetime', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.DateTimeBlock(required=False))], group='Fields')), ('image', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False))], group='Fields')), ('file', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False))], group='Fields')), ('multi_file', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False))], group='Fields')), ('group_toggle', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('help_link', wagtail.core.blocks.URLBlock(label='Help link', required=False)), ('required', wagtail.core.blocks.BooleanBlock(default=True, label='Required', required=False)), ('choices', wagtail.core.blocks.ListBlock(wagtail.core.blocks.CharBlock(label='Choice'), help_text='Please create only two choices for toggle. First choice will revel the group and the second hide it. Additional choices will be ignored.'))], group='Custom')), ('group_toggle_end', hypha.apply.stream_forms.blocks.GroupToggleEndBlock(group='Custom'))])),
+            ],
+            bases=(hypha.apply.stream_forms.models.BaseStreamForm, models.Model),
+        ),
+    ]
diff --git a/hypha/apply/projects/models/__init__.py b/hypha/apply/projects/models/__init__.py
index 2aeab4cc6bd89e11b3468d39c662d35c8381deb7..7794e9e2cec0dd0c1d67c447375c54744f5b528a 100644
--- a/hypha/apply/projects/models/__init__.py
+++ b/hypha/apply/projects/models/__init__.py
@@ -6,6 +6,7 @@ from .project import (
     DocumentCategory,
     PacketFile,
     Project,
+    ProjectApprovalForm,
     ProjectSettings,
 )
 from .report import Report, ReportConfig, ReportPrivateFiles, ReportVersion
@@ -13,6 +14,7 @@ from .vendor import BankInformation, DueDiligenceDocument, Vendor
 
 __all__ = [
     'Project',
+    'ProjectApprovalForm',
     'ProjectSettings',
     'Approval',
     'Contract',
diff --git a/hypha/apply/projects/models/project.py b/hypha/apply/projects/models/project.py
index e3c470cf519a62352fb126278bf48d9becb95453..10e5159f203d946c80dddf3c53f09e14ba938c6a 100644
--- a/hypha/apply/projects/models/project.py
+++ b/hypha/apply/projects/models/project.py
@@ -16,6 +16,7 @@ from django.dispatch.dispatcher import receiver
 from django.urls import reverse
 from django.utils import timezone
 from django.utils.translation import gettext_lazy as _
+from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
 from wagtail.contrib.settings.models import BaseSetting, register_setting
 from wagtail.core.fields import StreamField
 
@@ -372,6 +373,19 @@ class Project(BaseStreamForm, AccessFormData, models.Model):
     #     self.save(update_fields=['sent_to_compliance_at'])
 
 
+class ProjectApprovalForm(BaseStreamForm, models.Model):
+    name = models.CharField(max_length=255)
+    form_fields = StreamField(FormFieldsBlock())
+
+    panels = [
+        FieldPanel('name'),
+        StreamFieldPanel('form_fields'),
+    ]
+
+    def __str__(self):
+        return self.name
+
+
 @register_setting
 class ProjectSettings(BaseSetting):
     compliance_email = models.TextField("Compliance Email")
diff --git a/hypha/apply/projects/templates/application_projects/project_approval_form.html b/hypha/apply/projects/templates/application_projects/project_approval_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..8520b225d9c2a2e2a4d861e873aac9898ee9c2d4
--- /dev/null
+++ b/hypha/apply/projects/templates/application_projects/project_approval_form.html
@@ -0,0 +1,55 @@
+{% extends "base-apply.html" %}
+{% load i18n static %}
+{% block title %}Editing: {{object.title }}{% endblock %}
+{% block content %}
+<div class="admin-bar">
+    <div class="admin-bar__inner">
+        <h2 class="heading heading--no-margin">{% trans "Editing" %}: {{ object.title }}</h2>
+    </div>
+</div>
+
+{% include "forms/includes/form_errors.html" with form=form %}
+
+<div class="wrapper wrapper--light-grey-bg wrapper--form wrapper--sidebar">
+    <div class="wrapper--sidebar--inner">
+        <form class="form application-form" action="" method="post" enctype="multipart/form-data">
+            {% csrf_token %}
+            {{ form.media }}
+
+            {% for field in form %}
+                {% if field.field %}
+                    {% if field.field.multi_input_field %}
+                        {% include "forms/includes/multi_input_field.html" %}
+                    {% else %}
+                        {% include "forms/includes/field.html" %}
+                    {% endif %}
+                {% else %}
+                    {{ field.block }}
+                {% endif %}
+            {% endfor %}
+
+            {# Hidden fields needed e.g. for django-file-form. See `StreamBaseForm.hidden_fields` #}
+            {% for hidden_field in form.hidden_fields %}
+                {{ hidden_field }}
+            {% endfor %}
+
+            {% trans "Save draft" as save_draft %}
+            {% for button_name, button_type, button_value in buttons %}
+                <button class="button button--submit button--top-space button--{{ button_type }}" type="submit" name="{{ button_name }}" {% if button_value == save_draft %}formnovalidate{% endif %}>{{ button_value }}</button>
+            {% endfor %}
+        </form>
+    </div>
+</div>
+
+{% endblock %}
+
+{% block extra_js %}
+    <script src="{% static 'js/apply/list-input-files.js' %}"></script>
+    <script src="{% static 'js/apply/tinymce-word-count.js' %}"></script>
+    <script src="{% static 'js/apply/multi-input-fields.js' %}"></script>
+    <script src="{% static 'js/apply/submission-form-copy.js' %}"></script>
+    <script src="{% static 'js/apply/application-form-links-new-window.js' %}"></script>
+    {% if not show_all_group_fields %}
+    <script src="{% static 'js/apply/form-group-toggle.js' %}"></script>
+    {% endif %}
+{% endblock %}
diff --git a/hypha/apply/projects/tests/factories.py b/hypha/apply/projects/tests/factories.py
index a1e710afb1f5836c98606f814241e4dafc1d40db..50c7bee415d657efd57f2c4f30941352a4be8d17 100644
--- a/hypha/apply/projects/tests/factories.py
+++ b/hypha/apply/projects/tests/factories.py
@@ -5,6 +5,10 @@ from dateutil.relativedelta import relativedelta
 from django.utils import timezone
 
 from hypha.apply.funds.tests.factories import ApplicationSubmissionFactory
+from hypha.apply.stream_forms.testing.factories import (
+    FormDataFactory,
+    FormFieldsBlockFactory,
+)
 from hypha.apply.users.tests.factories import StaffFactory, UserFactory
 
 from ..models.payment import Invoice, InvoiceDeliverable, SupportingDocument
@@ -16,6 +20,7 @@ from ..models.project import (
     DocumentCategory,
     PacketFile,
     Project,
+    ProjectApprovalForm,
 )
 from ..models.report import Report, ReportConfig, ReportVersion
 
@@ -53,6 +58,18 @@ class DocumentCategoryFactory(factory.django.DjangoModelFactory):
         model = DocumentCategory
 
 
+class ProjectApprovalFormFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = ProjectApprovalForm
+
+    name = factory.Faker('word')
+    form_fields = FormFieldsBlockFactory
+
+
+class ProjectApprovalFormDataFactory(FormDataFactory):
+    field_factory = FormFieldsBlockFactory
+
+
 class ProjectFactory(factory.django.DjangoModelFactory):
     submission = factory.SubFactory(ApplicationSubmissionFactory)
     user = factory.SubFactory(UserFactory)
@@ -65,6 +82,12 @@ class ProjectFactory(factory.django.DjangoModelFactory):
 
     is_locked = False
 
+    form_fields = FormFieldsBlockFactory
+    form_data = factory.SubFactory(
+        ProjectApprovalFormDataFactory,
+        form_fields=factory.SelfAttribute('..form_fields'),
+    )
+
     class Meta:
         model = Project
 
diff --git a/hypha/apply/projects/views/project.py b/hypha/apply/projects/views/project.py
index 66f2b283f5a1065fae3e26fcbf7b8858f73f1335..b436eb319248176f131024e64ea9a093b193ed32 100644
--- a/hypha/apply/projects/views/project.py
+++ b/hypha/apply/projects/views/project.py
@@ -11,6 +11,7 @@ from django.shortcuts import get_object_or_404, redirect
 from django.urls import reverse, reverse_lazy
 from django.utils import timezone
 from django.utils.decorators import method_decorator
+from django.utils.functional import cached_property
 from django.utils.safestring import mark_safe
 from django.utils.translation import gettext as _
 from django.views import View
@@ -27,6 +28,7 @@ from django_tables2 import SingleTableMixin
 
 from hypha.apply.activity.messaging import MESSAGES, messenger
 from hypha.apply.activity.views import ActivityContextMixin, CommentFormView
+from hypha.apply.stream_forms.models import BaseStreamForm
 from hypha.apply.users.decorators import (
     approver_required,
     staff_or_finance_required,
@@ -589,9 +591,14 @@ class ProjectDetailPDFView(SingleObjectMixin, View):
 
 
 @method_decorator(staff_required, name='dispatch')
-class ProjectApprovalEditView(UpdateView):
-    form_class = ProjectApprovalForm
+class ProjectApprovalEditView(BaseStreamForm, UpdateView):
+    submission_form_class = ProjectApprovalForm
     model = Project
+    template_name = 'application_projects/project_approval_form.html'
+
+    def buttons(self):
+        yield ('submit', 'primary', _('Submit'))
+        # yield ('save', 'white', _('Save draft'))
 
     def dispatch(self, request, *args, **kwargs):
         project = self.get_object()
@@ -600,7 +607,48 @@ class ProjectApprovalEditView(UpdateView):
             return redirect(project)
         return super().dispatch(request, *args, **kwargs)
 
+    @cached_property
+    def approval_form(self):
+        if self.object.get_defined_fields():
+            approval_form = self.object
+        else:
+            approval_form = self.object.submission.page.specific.approval_form
+
+        return approval_form
+
+    def get_context_data(self, **kwargs):
+        return super().get_context_data(
+            title=self.object.title,
+            buttons=self.buttons(),
+            **kwargs
+        )
+
+    def get_defined_fields(self):
+        approval_form = self.object.submission.get_from_parent('approval_form')
+        if approval_form:
+            return approval_form.form_fields
+        return self.object.get_defined_fields()
+
+    def get_form_kwargs(self):
+        kwargs = super().get_form_kwargs()
+
+        if self.approval_form:
+            fields = self.approval_form.get_form_fields()
+        else:
+            fields = {}
+
+        kwargs['extra_fields'] = fields
+        kwargs['initial'].update(self.object.raw_data)
+        return kwargs
+
     def form_valid(self, form):
+        try:
+            form_fields = self.approval_form.form_fields
+        except AttributeError:
+            form_fields = []
+
+        form.instance.form_fields = form_fields
+
         return super().form_valid(form)