Hi  simflex,
I have created sample code which full-fill your requirement. Please read carefully and you need to modify as per your requirement.
HTML
<form id="form1" runat="server">
<div>
    <asp:GridView ID="gvIncome" AutoGenerateColumns="false" runat="server" OnRowDataBound="gvIncome_RowDataBound"
        OnRowDeleting="gvIncome_RowDeleting">
        <Columns>
            <asp:TemplateField HeaderText="Income">
                <ItemTemplate>
                    <asp:TextBox ID="txtspouseincome" placeholder="Income..." runat="server" Style="width: 200px;
                        height: 20px" class="form-control"></asp:TextBox>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText=" ">
                <ItemTemplate>
                    <asp:Button ID="ButtonAdd2" runat="server" Text="Add" OnClick="ButtonAdd_Click" CssClass="btnSuccess" />
                </ItemTemplate>
            </asp:TemplateField>
            <asp:CommandField ShowDeleteButton="True">
                <ControlStyle CssClass="grvDelButton" />
            </asp:CommandField>
        </Columns>
    </asp:GridView>
    <br />
    <br />
    <asp:GridView ID="gvSpouse" AutoGenerateColumns="false" runat="server" OnRowDataBound="gvSpouse_RowDataBound"
        OnRowDeleting="gvSpouse_RowDeleting">
        <Columns>
            <asp:TemplateField HeaderText="Spouse">
                <ItemTemplate>
                    <asp:TextBox ID="txtspouseincome1" placeholder="Spouse..." runat="server" Style="width: 200px;
                        height: 20px" class="form-control"></asp:TextBox>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText=" ">
                <ItemTemplate>
                    <asp:Button ID="ButtonAdd2" runat="server" Text="Add" OnClick="ButtonAdd_Click1"
                        CssClass="btnSuccess" />
                </ItemTemplate>
            </asp:TemplateField>
            <asp:CommandField ShowDeleteButton="True">
                <ControlStyle CssClass="grvDelButton" />
            </asp:CommandField>
        </Columns>
    </asp:GridView>
</div>
</form>
C#
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        this.SetInitialRow();
    }
}
private void SetInitialRow()
{
    DataTable dt = new DataTable();
    DataRow dr = null;
    dt.Columns.Add(new DataColumn("RowNumber", typeof(string)));
    dt.Columns.Add(new DataColumn("Column1", typeof(string)));
    dr = dt.NewRow();
    dr["RowNumber"] = 1;
    dr["Column1"] = string.Empty;
    dt.Rows.Add(dr);
    ViewState["CurrentTable" + 0] = dt;
    ViewState["CurrentTable" + 1] = dt;
    BindGridview();
}
private void BindGridview()
{
    DataTable dt = (DataTable)(ViewState["CurrentTable" + 0]);
    gvIncome.DataSource = dt;
    gvIncome.DataBind();
    DataTable dt1 = (DataTable)(ViewState["CurrentTable" + 1]);
    gvSpouse.DataSource = dt1;
    gvSpouse.DataBind();
}
// For Income...
protected void gvIncome_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.Header)
    {
        if (e.Row.RowIndex == -1)
        {
            ((CommandField)(((DataControlFieldCell)(e.Row.Cells[2])).ContainingField)).ShowDeleteButton = false;
        }
    }
    else
    {
        if (Convert.ToInt32(ViewState["rowIndex" + 0]) == e.Row.RowIndex)
        {
            ((CommandField)(((DataControlFieldCell)(e.Row.Cells[2])).ContainingField)).ShowDeleteButton = true;
        }
    }
}
// for Spouse...
protected void gvSpouse_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.Header)
    {
        if (e.Row.RowIndex == -1)
        {
            ((CommandField)(((DataControlFieldCell)(e.Row.Cells[2])).ContainingField)).ShowDeleteButton = false;
        }
    }
    else
    {
        if (Convert.ToInt32(ViewState["rowIndex" + 1]) == e.Row.RowIndex)
        {
            ((CommandField)(((DataControlFieldCell)(e.Row.Cells[2])).ContainingField)).ShowDeleteButton = true;
        }
    }
}
private void AddNewRowToGrid(int viewId, GridView gv)
{
    int rowIndex = 0;
    if (ViewState["CurrentTable" + viewId] != null)
    {
        DataTable dtCurrentTable = (DataTable)ViewState["CurrentTable" + viewId];
        DataRow drCurrentRow = null;
        if (dtCurrentTable.Rows.Count > 0)
        {
            for (int i = 1; i <= dtCurrentTable.Rows.Count; i++)
            {
                TextBox box1 = new TextBox();
                if (viewId == 0)
                {
                    box1 = (TextBox)gv.Rows[rowIndex].Cells[1].FindControl("txtspouseincome");
                }
                if (viewId == 1)
                {
                    box1 = (TextBox)gv.Rows[rowIndex].Cells[1].FindControl("txtspouseincome1");
                }
                drCurrentRow = dtCurrentTable.NewRow();
                drCurrentRow["RowNumber"] = i + 1;
                dtCurrentTable.Rows[i - 1]["Column1"] = box1.Text;
                rowIndex++;
            }
            dtCurrentTable.Rows.Add(drCurrentRow);
            ViewState["CurrentTable" + viewId] = dtCurrentTable;
            gv.DataSource = dtCurrentTable;
            gv.DataBind();
        }
    }
    else
    {
        Response.Write("ViewState is null");
    }
    SetPreviousData(viewId, gv);
}
private void SetPreviousData(int viewId, GridView gv)
{
    int rowIndex = 0;
    if (ViewState["CurrentTable" + viewId] != null)
    {
        DataTable dt = (DataTable)ViewState["CurrentTable" + viewId];
        if (dt.Rows.Count > 0)
        {
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                TextBox box1 = new TextBox();
                if (viewId == 0)
                {
                    box1 = (TextBox)gv.Rows[rowIndex].Cells[1].FindControl("txtspouseincome");
                }
                if (viewId == 1)
                {
                    box1 = (TextBox)gv.Rows[rowIndex].Cells[1].FindControl("txtspouseincome1");
                }
                box1.Text = dt.Rows[i]["Column1"].ToString();
                rowIndex++;
            }
        }
    }
}
protected void ButtonAdd_Click(object sender, EventArgs e)
{
    GridViewRow row = (sender as Button).NamingContainer as GridViewRow;
    if (gvIncome.Rows.Count - 1 == row.RowIndex)
    {
        ViewState["rowIndex" + 0] = row.RowIndex;
    }
    AddNewRowToGrid(0, gvIncome);
    this.BindGridview();
}
protected void ButtonAdd_Click1(object sender, EventArgs e)
{
    GridViewRow row = (sender as Button).NamingContainer as GridViewRow;
    if (gvSpouse.Rows.Count - 1 == row.RowIndex)
    {
        ViewState["rowIndex" + 1] = row.RowIndex;
    }
    AddNewRowToGrid(1, gvSpouse);
    this.BindGridview();
}
protected void gvSpouse_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
    int rowID = e.RowIndex;
    DeleteRow(e, rowID, 1, gvSpouse);
}
protected void gvIncome_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
    int rowID = e.RowIndex;
    DeleteRow(e, rowID, 0, gvIncome);
}
private void DeleteRow(GridViewDeleteEventArgs e, int rowID, int viewId, GridView gv)
{
    if (ViewState["CurrentTable" + viewId] != null)
    {
        DataTable dt = (DataTable)ViewState["CurrentTable" + viewId];
        if (dt.Rows.Count > 1)
        {
            if (e.RowIndex < dt.Rows.Count)
            {
                dt.Rows.Remove(dt.Rows[rowID]);
            }
        }
        ViewState["CurrentTable" + viewId] = dt;
        ViewState["rowIndex" + viewId] = rowID - 2;
        gv.DataSource = dt;
        gv.DataBind();
    }
    SetPreviousData(viewId, gv);
    this.BindGridview();
}
Vb.net
    Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        If Not IsPostBack Then
            Me.SetInitialRow()
        End If
    End Sub
    Private Sub SetInitialRow()
        Dim dt As New DataTable()
        Dim dr As DataRow = Nothing
        dt.Columns.Add(New DataColumn("RowNumber", GetType(String)))
        dt.Columns.Add(New DataColumn("Column1", GetType(String)))
        dr = dt.NewRow()
        dr("RowNumber") = 1
        dr("Column1") = String.Empty
        dt.Rows.Add(dr)
        ViewState("CurrentTable" & 0) = dt
        ViewState("CurrentTable" & 1) = dt
        BindGridview()
    End Sub
    Private Sub BindGridview()
        Dim dt As DataTable = DirectCast(ViewState("CurrentTable" & 0), DataTable)
        gvIncome.DataSource = dt
        gvIncome.DataBind()
        Dim dt1 As DataTable = DirectCast(ViewState("CurrentTable" & 1), DataTable)
        gvSpouse.DataSource = dt1
        gvSpouse.DataBind()
    End Sub
    Protected Sub gvIncome_RowDataBound(sender As Object, e As GridViewRowEventArgs)
        If e.Row.RowType = DataControlRowType.Header Then
            If e.Row.RowIndex = -1 Then
                DirectCast(DirectCast(e.Row.Cells(2), DataControlFieldCell).ContainingField, CommandField).ShowDeleteButton = False
            End If
        Else
            If Convert.ToInt32(ViewState("rowIndex" & 0)) = e.Row.RowIndex Then
                DirectCast(DirectCast(e.Row.Cells(2), DataControlFieldCell).ContainingField, CommandField).ShowDeleteButton = True
            End If
        End If
    End Sub
    Protected Sub gvSpouse_RowDataBound(sender As Object, e As GridViewRowEventArgs)
        If e.Row.RowType = DataControlRowType.Header Then
            If e.Row.RowIndex = -1 Then
                DirectCast(DirectCast(e.Row.Cells(2), DataControlFieldCell).ContainingField, CommandField).ShowDeleteButton = False
            End If
        Else
            If Convert.ToInt32(ViewState("rowIndex" & 1)) = e.Row.RowIndex Then
                DirectCast(DirectCast(e.Row.Cells(2), DataControlFieldCell).ContainingField, CommandField).ShowDeleteButton = True
            End If
        End If
    End Sub
    Private Sub AddNewRowToGrid(viewId As Integer, gv As GridView)
        Dim rowIndex As Integer = 0
        If ViewState("CurrentTable" & viewId) IsNot Nothing Then
            Dim dtCurrentTable As DataTable = DirectCast(ViewState("CurrentTable" & viewId), DataTable)
            Dim drCurrentRow As DataRow = Nothing
            If dtCurrentTable.Rows.Count > 0 Then
                For i As Integer = 1 To dtCurrentTable.Rows.Count
                    Dim box1 As New TextBox()
                    If viewId = 0 Then
                        box1 = DirectCast(gv.Rows(rowIndex).Cells(1).FindControl("txtspouseincome"), TextBox)
                    End If
                    If viewId = 1 Then
                        box1 = DirectCast(gv.Rows(rowIndex).Cells(1).FindControl("txtspouseincome1"), TextBox)
                    End If
                    drCurrentRow = dtCurrentTable.NewRow()
                    drCurrentRow("RowNumber") = i + 1
                    dtCurrentTable.Rows(i - 1)("Column1") = box1.Text
                    rowIndex += 1
                Next
                dtCurrentTable.Rows.Add(drCurrentRow)
                ViewState("CurrentTable" & viewId) = dtCurrentTable
                gv.DataSource = dtCurrentTable
                gv.DataBind()
            End If
        Else
            Response.Write("ViewState is null")
        End If
        SetPreviousData(viewId, gv)
    End Sub
    Private Sub SetPreviousData(viewId As Integer, gv As GridView)
        Dim rowIndex As Integer = 0
        If ViewState("CurrentTable" & viewId) IsNot Nothing Then
            Dim dt As DataTable = DirectCast(ViewState("CurrentTable" & viewId), DataTable)
            If dt.Rows.Count > 0 Then
                For i As Integer = 0 To dt.Rows.Count - 1
                    Dim box1 As New TextBox()
                    If viewId = 0 Then
                        box1 = DirectCast(gv.Rows(rowIndex).Cells(1).FindControl("txtspouseincome"), TextBox)
                    End If
                    If viewId = 1 Then
                        box1 = DirectCast(gv.Rows(rowIndex).Cells(1).FindControl("txtspouseincome1"), TextBox)
                    End If
                    box1.Text = dt.Rows(i)("Column1").ToString()
                    rowIndex += 1
                Next
            End If
        End If
    End Sub
    Protected Sub ButtonAdd_Click(sender As Object, e As EventArgs)
        Dim row As GridViewRow = TryCast(TryCast(sender, Button).NamingContainer, GridViewRow)
        If gvIncome.Rows.Count - 1 = row.RowIndex Then
            ViewState("rowIndex" & 0) = row.RowIndex
        End If
        AddNewRowToGrid(0, gvIncome)
        Me.BindGridview()
    End Sub
    Protected Sub ButtonAdd_Click1(sender As Object, e As EventArgs)
        Dim row As GridViewRow = TryCast(TryCast(sender, Button).NamingContainer, GridViewRow)
        If gvSpouse.Rows.Count - 1 = row.RowIndex Then
            ViewState("rowIndex" & 1) = row.RowIndex
        End If
        AddNewRowToGrid(1, gvSpouse)
        Me.BindGridview()
    End Sub
    Protected Sub gvSpouse_RowDeleting(sender As Object, e As GridViewDeleteEventArgs)
        Dim rowID As Integer = e.RowIndex
        DeleteRow(e, rowID, 1, gvSpouse)
    End Sub
    Protected Sub gvIncome_RowDeleting(sender As Object, e As GridViewDeleteEventArgs)
        Dim rowID As Integer = e.RowIndex
        DeleteRow(e, rowID, 0, gvIncome)
    End Sub
    Private Sub DeleteRow(e As GridViewDeleteEventArgs, rowID As Integer, viewId As Integer, gv As GridView)
        If ViewState("CurrentTable" & viewId) IsNot Nothing Then
            Dim dt As DataTable = DirectCast(ViewState("CurrentTable" & viewId), DataTable)
            If dt.Rows.Count > 1 Then
                If e.RowIndex < dt.Rows.Count Then
                    dt.Rows.Remove(dt.Rows(rowID))
                End If
            End If
            ViewState("CurrentTable" & viewId) = dt
            ViewState("rowIndex" & viewId) = rowID - 2
            gv.DataSource = dt
            gv.DataBind()
        End If
        SetPreviousData(viewId, gv)
        Me.BindGridview()
    End Sub
Screenshot
